USACO-Section 2.2 Preface Numbering(数学)

3199 ワード

説明
一種類の本の序言はローマ数字でページ番号をつけたものだ.従来のローマ数字は、特定の数値を単一のアルファベットで表しています.以下は標準数字表です.
I 1  L 50  M 1000
V 5  C 100
X 10 D 500

最大3つの同じ10 nとして表すことができる数字(I,X,C,M)は、それらの和を表すために連続的に一緒に置くことができる.
III=3
CCC=300

5 x 10 nと表すことができる文字(V,L,D)は連続して現れない.
次のルールに加えて、一般的には、文字は減算順に連続して表示されます.
CCLXVIII = 100+100+50+10+5+1+1+1 = 268

場合によっては、10 nと表すことができる数が、それより1または2大きい数の前に現れる(IはVまたはXの前にあり、XはLまたはCの前にあるなど).この場合、数値は後の数に等しく、前の数を減算します.
IV = 4
IX = 9
XL = 40

This compound mark forms a unit and may not be combined to make another compound mark (e.g., IXL is wrong for 39; XXXIX is correct).
XD、IC、XMのような表現は違法です.前の数は後ろの数よりずっと小さいからです.XD(490の誤った表現)については、CDXCと書くことができる.IC(99の誤った表現)については、XCIXと書くことができる.XM(990の誤った表現)については、CMXCと書くことができる.90 is expressed XC and not LXL, since L followed by X connotes that successive marks are X or smaller (probably, anyway).
N(1<=N<3500)、序文のページ番号を指定します.1ページ目からNページ目まで、Iがいくつ、Vがいくつ、など(小さい順)を集計してください.表示されていない文字は出力しないでください.
例えばN=5であると,ページ番号は,I,II,III,IV,V.の合計7個のIが出現し,2個のVが出現する.
書式設定
PROGRAM NAME: preface
INPUT FORMAT:
(preface.in)
整数N.
OUTPUT FORMAT:
(preface.out)
各行に1つの文字と1つの数字kがあり、この文字がk回現れたことを示す.文字は、数値テーブルの増分順に出力する必要があります.
SAMPLE INPUT
5

SAMPLE OUTPUT
I 7
V 2

こんなに简単な问题をすぐに作ることができなくて、长い间、列挙の方法があるのに数学の方法を使わなければなりません..
スタートアルゴリズムが合っているかもしれませんが、下付き境界と負数を処理するのを忘れた場合、結果はずっと間違っています.の
/*
ID: your_id_here 
PROG: preface
LANG: C++
*/
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int nn[3][10]={0,1,2,3,1,0,1,2,3,1,
                     0,0,0,0,1,1,1,1,1,0,
                     0,0,0,0,0,0,0,0,0,1};
const int nm[3][10]={0,1,3,6,7,7,8,10,13,14,
                     0,0,0,0,1,2,3,4,5,5,
                     0,0,0,0,0,0,0,0,0,1};
int n,num[11],t,t1,t2,tt,tp;//num     ,     ,OJ ...
char ch[8]="IVXLCDM";

int main() {
    int i;
    freopen("preface.in","r",stdin);
    freopen("preface.out","w",stdout);
    while(1==scanf("%d",&n)) {
        for(i=0;i<8;++i)
            num[i]=0;
        i=0,tp=1,tt=1,t=n;
        while(t) {
            t1=t/10;
            tt=t%10-1;
            if(tt==-1)//           ,  tt -1     0
                tt=0;
            //            :       abc
            //Ⅰ:     
            //①ab( c     ) 0~9      ②1 0~c-1      ③n%tp+1( c     +1=0+1) c   
            //Ⅱ:     
            //①a( b     ) 0~9      ②1 0~b-1      ③n%tp+1( b     +1=b+1) b   
            //Ⅲ:     
            //①0( a     ) 0~9      ②1 0~a-1      ③n%tp+1( b     +1=a+1) a   
            num[i]+=t1*nm[0][9]*tp+nm[0][tt]*tp+(n%tp+1)*nn[0][t%10];
            num[i+1]+=t1*nm[1][9]*tp+nm[1][tt]*tp+(n%tp+1)*nn[1][t%10];
            num[i+2]+=t1*nm[2][9]*tp+nm[2][tt]*tp+(n%tp+1)*nn[2][t%10];
            t=t1;
            i+=2;
            tp*=10;
        }
        i=0;
        while(num[i]) {
            printf("%c %d
",ch[i],num[i]); ++i; } } return 0; }