USACO Preface Numbering

本文探讨了如何使用枚举方法将整数转换为罗马数字,并通过优化算法提高效率。详细介绍了罗马数字的构成规则,包括数字表的构建、数学问题的分析以及数学统计方法的应用,最终实现了一个高效且易于理解的转换过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我很不争气的用了最简单的枚举,觉得自己在对照string数组分析字母的函数处理上还是不错滴

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

#include <iostream>
#include <fstream>
#include <vector>
#include <string>

using namespace std;
int M, D, C, L, X, V, I;
int N;

static string s[4][10] = {
	{ "", "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"}  //千
};

void rome(string curr) {
	char c;
	for(int i = 0; i < curr.size(); i++) {
		c = curr[i];
		switch(c) {
			case 'M': M++; break;
			case 'D': D++; break;
			case 'C': C++; break;
			case 'L': L++; break;
			case 'X': X++; break;
			case 'V': V++; break;
			case 'I': I++; break;
		}
	}
}

void analyze(int n) {
	string curr;
	int digit;

	digit = n / 1000;
	n = n % 1000;
	curr = s[3][digit];
	rome(curr);

	digit = n / 100;
	n = n % 100;
	curr = s[2][digit];
	rome(curr);

	digit = n / 10;
	n = n % 10;
	curr = s[1][digit];
	rome(curr);

	digit = n / 1;
	curr = s[0][digit];
	rome(curr);
}

int main() {
	int N;
	//input
	ifstream fin("preface.in");
	fin>>N;
	fin.close();
	

	//BODY
	for(int i = 1; i <= N; i++) {
		analyze(i);
	}
	
	//Output
	ofstream fout("preface.out");
	if(I > 0) fout<<"I"<<" "<<I<<endl;
	if(V > 0) fout<<"V"<<" "<<V<<endl;
	if(X > 0) fout<<"X"<<" "<<X<<endl;
	if(L > 0) fout<<"L"<<" "<<L<<endl;
	if(C > 0) fout<<"C"<<" "<<C<<endl;
	if(D > 0) fout<<"D"<<" "<<D<<endl;
	if(M > 0) fout<<"M"<<" "<<M<<endl;
	fout.close();

	return 0;
}

Preface Numbering (preface)

分析一:枚举

首先大多数人都能想到的算法就是枚举,因为枚举容易易懂。虽说枚举不超时,但是我们也应该尽可能优化,使程序更快速。所以我们应该制造一个数字表:

const

shu:array[1..4,0..9] 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',,,,,,));//千

那么之后进行枚举时就可以加快速度……

分析二:数学问题

这道题的n只有3000多,从1~n把根据题目转换成字母,然后统计出现次数也不会超时。不过这里介绍另一种更高效的算法。

0~9中IVX出现的次数和10~19,20~29,x0~x9中的相同(其它字母都未出现)。0~99中仅十位产生的字母中,字母出现的次数相同,不同的是字母成了XLC,后移了2位。

我们把n按十进制位从低到高的顺序统计每位出现的字母次数。

以n=234为例,

仅个位:23个0~9的次数,1个0~3的次数,1个4的次数。(IVX)

仅十位:2个0~9的次数*10,1个0~2的次数*10,5个3的次数。(XLC)

仅百位:0个0~9的次数*100,1个0~1的次数*100,35个2的次数。(CDM)

分析三

数学统计首先,不考虑顺序,那么任意一个数对应的罗马数字,都可以用其他几个n×10^k表示,比如999=900+90+9=CM+XC+IX;所以我们预先处理出1~9,10~90,100~900,1000~3000这几个数所对应的字符,这样再枚举效率就要高些(当然对于3000的数据看不太出来,要是10^6试试……)。

分析四

每一位对应三个字母

个位 I V X

十位 X L C

百位 C D M

千位 M

字母 A B C

然后:1对应A,2对应AA,3对应AAA,4对应AB,5对应B,6对应BA,7对应BAA,8对应BAAA,9对应C。

这样先写一个1..9,A..C的常量数组,然后对每一个数的每一位进行统计就OK了。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值