【USACO题库】2.2.1 Preface Numbering序言页码(数学+枚举)

来源:互联网 发布:yum强制重新安装 编辑:程序博客网 时间:2024/06/03 19:12

【题目描述】

         一类书的序言是以罗马数字标页码的。传统罗马数字用单个字母表示特定的数值,一下是标准数字表:

         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出现。

输入:
         一个整数N。

样例输入:
         5

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

样例输出:
         I 7
         V 2

【解题思路】

     这道题我刚开始根本不会怎么按照题目去模拟,可是后来想一想,发现数据只有3000,也就是说,只有4个数位,而每个数位的情况都是固定的:

         个位:1,2,3,4,5,6,7,8,9(1-9);

         十位:1,2,3,4,5,6,7,8,9(10-90);

         百位:1,2,3,4,5,6,7,8,9(100-900);

         千位:1,2,3(1000-3000)

         所以,我们预先处理好这30个位置的情况,再做,就可以了。

【代码实现】

var         i,j,n,ans:longint;         s:string;         k:array['A'..'Z'] of longint;         num:array[1..30] of longint=(1,2,3,4,5,6,7,8,9,10,20,30,40,50,60,70,80,90,100,200,300,400,500,600,700,800,900,1000,2000,3000);//这个是每个数位代表对应的数。         ch:array[1..30] of string=('I','II','III','IV','V','VI','VII','VIII','IX','X','XX','XXX','XL','L','LX','LXX','LXXX','XC','C','CC','CCC','CD','D','DC','DCC','DCCC','CM','M','MM','MMM');//这个是对应数位的罗马数字。begin         readln(n);         for i:=1 to n do         begin                 ans:=i;                 s:='';                 for j:=30 downto 1 do//一共30种                 begin                         if ans>=num[j] then//如果符合其中一种                         begin                                 dec(ans,num[j]);                                 s:=s+ch[j];                         end;                         if ans=0 then break;//如果到0,就是减完了,就退出                 end;                 for j:=1 to length(s) do                         inc(k[s[j]]);//累加每个罗马数字的个数         end;         s:='IVXLCDM';         for i:=1 to length(s) do                 if k[s[i]]>0 then writeln(s[i],' ',k[s[i]]);//输出即可end.
1 0
原创粉丝点击