1025. 【USACO题库】2.2.1 Preface Numbering序言页码

文章目录

  • 题目描述
  • 输入
  • 输出
  • 样例输入
  • 样例输出
  • 题解
  • 代码

题目描述

一类书的序言是以罗马数字标页码的。传统罗马数字用单个字母表示特定的数值,一下是标准数字表:
I 1 L 50 M 1000
V 5 C 100
X 10 D 500
最多3个可以表示为10n的数字(I,X,C,M)可以连续放在一起,表示它们的和:
III=3
CCC=300
可表示为5x10n的字符(V,L,D)从不连续出现。
除了下一个规则,一般来说,字符以递减的顺序接连出现:
CCLXVIII = 100+100+50+10+5+1+1+1 = 268
有时,一个可表示为10^n的数出现在一个比它大的数前(I在V或X前面,X在L或C前面,等等)。在这种情况下,数值等于后面的那个数减去前面的那个数:
IV = 4
IX = 9
XL = 40
像XD, IC, 和XM这样的表达是非法的,因为前面的数比后面的数小太多。对于XD(490的错误表达),可以写成 CDXC; 对于IC(99的错误表达),可以写成XCIX; 对于XM(990的错误表达),可以写成CMXC。
给定N(1 <= N < 3,500), 序言的页码数,请统计在第1页到第N也中,有几个I出现,几个V出现,等等 (从小到大的顺序)。不要输出并没有出现过的字符。
比如N = 5, 那么页码数为: I, II, III, IV, V. 总共有7个I出现,2个V出现。

输入

从文件 preface.in 中读入数据。
一个整数N。

输出

输出到文件 preface.out 中。
每行一个字符和一个数字k,表示这个字符出现了k次。字符必须按数字表中的递增顺序输出。

样例输入

5

样例输出

I 7
V 2

题解

思路:
首先罗马字母的定义和转化

(1):如果要转换的数字是一个字母, 那么我们的字母一定是那个字母
(2):如果数字只有一个数位有字母
比如100,200,1,90 表示整十数,整百数,整千数等

int p(int val,char str[]) // 将val -> str(val只有一个数位有数字)
{
	char tmp[128]={0};
	sprintf(tmp,"%d",val);
	int first_val = tmp[0] - '0'; // 取出第一个位置
	int Size_val = strlen(tmp); // 取出长度
	int p = pow(10,Size_val-1);
	if (first_val == 0) return 1;
	if (first_val <= 3) // 如果小于等于3
	{
		for (int i=0;i<first_val;i++) str[i] = Buf[p];
	}
	else if (first_val == 4)
	{
		str[0] = Buf[p];
		str[1] = Buf[p*5];
	}
	else if (first_val == 5) str[0] = Buf[p*5];
	else if (first_val <= 8) {
		str[0] = Buf[p*5];
		for (int i=1;i<=first_val-5;i++) str[i] = Buf[p];
	}
	else if (first_val == 9) str[0] = Buf[p*10], str[1] = Buf[p];
	return 0;
}

(3):如果数字是其他的数字, 比如是783
计算出来就是700的罗马数字+80的罗马数字+3的罗马数字
即DCC+LXXX+VII 所以数字是DCCLXXXVII

代码

#include 
#include 
#include 
#include 
#include 
using std::pair;
char Buf[1024]; 
int cnt[128];
const char* c_number = "IVXLCDM";
inline void Print(char c)
{
	if (cnt[c]) printf("%c %d\n",c,cnt[c]);
}
int p(int val,char str[]) // 将val -> str(val只有一个数位有数字)
{
	char tmp[128]={0};
	sprintf(tmp,"%d",val);
	int first_val = tmp[0] - '0'; // 取出第一个位置
	int Size_val = strlen(tmp); // 取出长度
	int p = pow(10,Size_val-1);
	if (first_val == 0) return 1;
	if (first_val <= 3) // 如果小于等于3
	{
		for (int i=0;i<first_val;i++) str[i] = Buf[p];
	}
	else if (first_val == 4)
	{
		str[0] = Buf[p];
		str[1] = Buf[p*5];
	}
	else if (first_val == 5) str[0] = Buf[p*5];
	else if (first_val <= 8) {
		str[0] = Buf[p*5];
		for (int i=1;i<=first_val-5;i++) str[i] = Buf[p];
	}
	else if (first_val == 9) str[0] = Buf[p*10], str[1] = Buf[p];
	return 0;
}
void dg(int val,char ans[128])
{
	char str[128] = {0};
	sprintf(str,"%d",val);
	int Size = strlen(str);
	for (int pos=0;pos<Size;pos++)
	{
		int tmp = str[pos] - '0';
		char buf[128]={0};
		tmp *= (pow(10,Size-pos-1));
		//printf("%d\n",tmp);
		p(tmp,buf);
		strcat(ans,buf);
	}
}
int main()
{
	freopen("preface.in","r",stdin), freopen("preface.out","w",stdout);
	Buf[1] = 'I', Buf[5] = 'V', Buf[10] = 'X', Buf[50] = 'L', Buf[100] = 'C', Buf[500] = 'D', Buf[1000] = 'M';
	char str[128] = {0};
	int val;
	scanf("%d",&val);
	for (int i=1;i<=val;i++)
	{
		memset(str,0,sizeof(str));
		dg(i,str);
		int Size = strlen(str);
		
		for (int j=0;j<Size;j++) {
			cnt[str[j]]++;
		}
	}
	
	for (int i=0;i<7;i++) Print(c_number[i]);
	return 0;
}

你可能感兴趣的:(粉丝才可以看的NC题解,算法)