USACO Section 2.2 Preface Numbering

题目原文

Preface Numbering

A certain book's prefaces are numbered in upper case Roman numerals. Traditional Roman numeral values use a single letter to represent a certain subset of decimal numbers. Here is the standard set:

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

As many as three of the same marks that represent 10n may be placed consecutively to form other numbers:

  • III is 3
  • CCC is 300

Marks that have the value 5x10n are never used consecutively.

Generally (with the exception of the next rule), marks are connected together and written in descending order to form even more numbers:

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

    Sometimes, a mark that represents 10^n is placed before a mark of one of the two next higher values (I before V or X; X before L or C; etc.). In this case, the value of the smaller mark is SUBTRACTED from the mark it precedes:

    • 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).

    Compound marks like XD, IC, and XM are not legal, since the smaller mark is too much smaller than the larger one. For XD (wrong for 490), one would use CDXC; for IC (wrong for 99), one would use XCIX; for XM (wrong for 990), one would use CMXC. 90 is expressed XC and not LXL, since L followed by X connotes that successive marks are X or smaller (probably, anyway).

    Given N (1 <= N < 3,500), the number of pages in the preface of a book, calculate and print the number of I's, V's, etc. (in order from lowest to highest) required to typeset all the page numbers (in Roman numerals) from 1 through N. Do not print letters that do not appear in the page numbers specified.

    If N = 5, then the page numbers are: I, II, III, IV, V. The total number of I's is 7 and the total number of V's is 2.

    PROGRAM NAME: preface

    INPUT FORMAT

    A single line containing the integer N.

    SAMPLE INPUT (file preface.in)

    5
    

    OUTPUT FORMAT

    The output lines specify, in ascending order of Roman numeral letters, the letter, a single space, and the number of times that letter appears on preface page numbers. Stop printing letter totals after printing the highest value letter used to form preface numbers in the specified set.

    SAMPLE OUTPUT (file preface.out)

    I 7
    V 2


分析

题目首先介绍了罗马数字的书写方式,罗马数字包括了I,V,X,L,C,D,M,分别表示1,5,10,50,100,500,1000。罗马数字采用累加的方式表示,但必要的时候也使用减法。十以内的可以表示为如下:
I 1
II 2
III 3
IV 4
V 5
VI 6
VII 7
VIII 8
IX 9
可以看出,1~3是 I 的累加,4是V和 I 相减,5~8是V和 I 的相加,9是X和I的相减。个位数如此,十位、百位、千位也是类似的规律。本文通过对输入的十进制数逐位判断来计算所有每个罗马数字字符出现的次数。在统计罗马数字字符个数的时候,可以使用条件语句判断,也可以预先将上述规律存储在一张表中以方便读取。预先存在表中可以减少代码篇幅,但是个人认为没那么直观了,因此本文还是使用条件语句来判断。

提交代码

/*
ID: 
PROG: preface
LANG: C++
*/

#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <string>
#include <math.h>
#include <limits>
#include <map>
using namespace std;

char set[]={'I','V','X','L','C','D','M'};

enum di{I=0,V,X,L,C,D,M};

std::vector<int> cnt(7,0);

void cal(int N)
{
	int i = 0;
	while(N!=0)
	{	
		int m = N % 10;
		if(i==0)
		{	
			if(m<4)
			{
				cnt[I] += m;
			}
			else if(m==4)
			{
				cnt[I] += 1;
				cnt[V] += 1;
			}
			else if(m>=5 && m<9)
			{
				cnt[I] += m-5;
				cnt[V] += 1;
			}
			else 
			{
				cnt[X] += 1;
				cnt[I] += 1;
			}
		}
		else if(i==1)
		{
			if(m<4)
			{
				cnt[X]+=m;
			}
			else if(m == 4)
			{
				cnt[X]+=1;
				cnt[L]+=1;
			}
			else if(m >=5 && m<9)
			{
				cnt[X] += m - 5;
				cnt[L] += 1;
			}
			else
			{
				cnt[X] += 1;
				cnt[C] += 1;
			}
		}
		else if(i==2)
		{
			if(m<4)
			{
				cnt[C]+=m;
			}
			else if(m == 4)
			{
				cnt[C]+=1;
				cnt[D]+=1;
			}
			else if(m >=5 && m<9)
			{
				cnt[C] += m - 5;
				cnt[D] += 1;
			}
			else
			{
				cnt[C] += 1;
				cnt[M] += 1;
			}
		}
		else if(i==3)
		{
			cnt[M] += m;
		}
		i++;
		N = (N-m)/10;
	}
}

int main()
{
	ifstream cin("preface.in");
	ofstream cout("preface.out");
	int N; cin >> N;

	for(int i=1;i<=N;i++)
	{
		cal(i);
	}

	for(int i=0;i!=cnt.size();i++)
	{
		if(cnt[i]==0)
			break;
		cout << set[i] <<" " << cnt[i] << endl;
	}
	return 0;
}

提交结果

TASK: preface
LANG: C++

Compiling...
Compile: OK

Executing...
   Test 1: TEST OK [0.003 secs, 3500 KB]
   Test 2: TEST OK [0.003 secs, 3500 KB]
   Test 3: TEST OK [0.005 secs, 3500 KB]
   Test 4: TEST OK [0.003 secs, 3500 KB]
   Test 5: TEST OK [0.003 secs, 3500 KB]
   Test 6: TEST OK [0.000 secs, 3500 KB]
   Test 7: TEST OK [0.016 secs, 3500 KB]
   Test 8: TEST OK [0.003 secs, 3500 KB]

All tests OK.

官方参考答案

官方给出了好多种参考答案,这里只贴最后一种看起来短小精悍的。
#include <fstream>
using namespace std;
int count[7];
int mult[6] = {5, 2, 5, 2, 5, 2}; // The factors between consecutive roman
				  // numeral letter values.
char roman[] = "IVXLCDM";
int vals[7] = {1, 5, 10, 50, 100, 500, 1000};

int main() {
    ofstream fout ("preface.out");
    ifstream fin ("preface.in");
    int n;
    fin >> n;

    for (int i = 1; i <= n; i++) {
	for (int j = 0, temp = i; temp != 0; j++) {
             // If there are more than three of the current letter.
	    if (temp % mult[j] > 3) {
		count[j]++;
                // Checks if it can have a two letter difference
		// (ie. IX instead of IV).
	        if (temp / mult[j] > 0 && i % vals[j + 2] > vals[j + 1]) {
	            count[j + 2]++;
     	            temp -= mult[j];
                } else
		    count[j + 1]++;
	    } else
		count[j] += temp % mult[j];
	    temp /= mult[j];
	}
    }
    for (int i = 0; i < 7; i++)
     if (count[i])
         fout << roman[i] << " " << count[i] << endl;
    return 0;
}

THE END



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值