P1465 序言页码 Preface Numbering(规律+打表)

题目描述

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

I 1 V 5 X 10 L 50 C 100 D 500 M 1000

最多3个同样的可以表示为10n的数字(I,X,C,M)可以连续放在一起,表示它们的和:

III=3 CCC=300

可表示为5x10n的字符(V,L,D)从不连续出现。

除了下一个规则,一般来说,字符以递减的顺序接连出现:

CCLXVIII = 100+100+50+10+5+1+1+1 = 268

有时,一个可表示为10n的数出现在一个比它大1级或2级的数前(I在V或X前面,X在L或C前面,等等)。在这种情况下,数值等于后面的那个数减去前面的那个数:

IV = 4 IX = 9 XL = 40

一个数 用罗马数字来表示 有且仅有一种 而且不能复合嵌套使用(比如I是1 X是10 有人可能要说 IXL就能表示50-10-1 但是IXL绝对不能用来表达39 ) (那么39用什么来表示呢 XXXIX是唯一 而且正确的选择- -)

像XD, IC, 和XM这样的表达是非法的,因为前面的数比后面的数小太多。对于XD(490的错误表达),可以写成 CDXC; 对于IC(99的错误表达),可以写成XCIX; 对于XM(990的错误表达),可以写成CMXC。 90 写成 XC 而不是 LXL, 因为 L 后面的 X 意味着后继标记是 X 或者更小 (不管怎样,可能吧)(等同于阿拉伯数字 每位 数字分别表示)。

给定N(1 <= N < 3,500), 序言的页码数,请统计在第1页到第N页中,有几个I出现,几个V出现,等等 (从小到大的顺序)。不要输出没有出现过的字符。

比如N = 5, 那么页码数为: I, II, III, IV, V. 总共有7个I出现,2个V出现。

输入输出格式

输入格式:

 

一个整数N。

 

输出格式:

 

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

 

输入输出样例

输入样例#1: 

5

输出样例#1: 

I 7
V 2

说明

翻译来自NOCOW

USACO 2.2

题意:

罗马数字和阿拉伯数字直接可以互相转换,给出一个阿拉伯数字N,计算从1-N这些数直接有多少个 IVXLCDM这些字符

题意比较难理解,先列出一些罗马数字和阿拉伯数字的对照

1

I

2

II

3

III

4

IV

5

V

6

VI

7

VII

8

VIII

9

IX

10

X

11

XI

12

XII

13

XIII

14

XIV

15

XV

16

XVI

17

XVII

18

XVIII

19

XIX

20

XX

21

XXI

22

XXII

23

XXIII

24

XXIV

25

XXV

26

XXVI

27

XXVII

28

XXVIII

29

XXIX

30

XXX

31

XXXI

32

XXXII

33

XXXII

34

XXXIV

35

XXXV

36

XXXVI

37

XXXVII

38

XXXVIII

39

XXXIX

40

XL

不难发现一个多位数的由每个1-10和十的倍数的数拼接组成。比如29是XXIX,那么9是IX,20是XX。这样就可以先列出1-10的数,然后递推打表。

下面谁是我自己找的1-30的数据。

AC代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
const int MOD=int(1e9)+7;
using namespace std;
int i,j,k,l;
int cnt[10];
char str[]=" IVXLCDM";
int cunt[4][3]={
    {1, 2, 3},
    {3, 4 ,5},
    {5, 6 ,7},
    {7, 0, 0}
    };//N最大是四位数,所以只要四组
int Roma[10][3]={
    {0,0,0},{1,0,0},{2,0,0},{3,0,0},
    {1,1,0},{0,1,0},{1,1,0},{2,1,0},{3,1,0},
    {1,0,1}
};

void mix(int x)
{
    for(int i=0;x;i++,x/=10)
    {
        int j=x%10;
        for(int k=0;k<3;k++)
            cnt[cunt[i][k]]+=Roma[j][k];
    }
}

int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        for(int i=1; i<=n; i++)
        mix(i);
      for(int i=1; i<=7; i++)
        if(cnt[i])
         cout<<str[i]<<' '<<cnt[i]<<endl;
    }

    return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值