题解
这道有点意思,本来很快写完的,被一个bug弄得怀疑人生了(结果发现是自己不仔细…)。
我的方法是 将数字转译成罗马数字,在这过程中做记录就好了。
肯定有纯数学的方法,直接递推出来,大家可以尝试一下。
大概的翻译算法为: 设给定待翻译数字为 n
1. 求出 n 最临近的区间 , 即n属于[sma, big ) // sma,big 显然是罗马数字中的基本数,要特殊处理相等情况
2. 确定这个区间的类型,有两种// 观察可知 [1,5) [5,10) 区间前后比率不同
3. 确定n在此区间中是位于前方还是后方 // 前方(可累计三次) 后方(类似IV) 的标记方法不同
4. 根据n所在的位置,将n减去 x数,并于此时做累计直到n的区间发生变化//x数 为不大于n的最大 罗马基本数 如 I于V I于X
5. 重复上述步骤直到n为0
代码
#include <iostream>
#include <cstdio>
#include <fstream>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
int n,m,b,d;
int base_num[] = {1,5,10,50,100,500,1000,5000};//7+1 in case of out range
char base_char[] = {'I','V','X','L','C','D','M'};
int cal_char[28];// count for those chars
int getSma(int num){
int ret=-1;
for(int i=0;i<7;i++){
if(base_num[i] <= num){
ret = base_num[i];
}else break;
}
return ret;
}
void pr(int num){
int sma_pos,big_pos,sma,big;
int t_ratio;
int tmp_sma,tmp_big;
while( num != 0){
// 1. sma & big
for(int i=0;i<7;i++){
if(base_num[i] <= num){
sma_pos = i;
big_pos = i+1;
sma = base_num[i];
big = base_num[i+1];
}else break;
}
if( num == sma ){ // special case
cal_char[ base_char[sma_pos] -'A' ]++;
//cout<<base_char[sma_pos];
num -= sma;
continue;
}
// 2. type detect && ratio cal
if( sma*2 == big) {t_ratio = 4;}
else {t_ratio = 3;}
tmp_sma = sma;
// 3. base on type. minus the body x
if( (big - num)*t_ratio > (num - sma)){ // near sma
while(tmp_sma == sma){
cal_char[ base_char[sma_pos] - 'A' ] ++;
// cout<< base_char[sma_pos] ;
num -= sma;
tmp_sma = getSma(num);
}
}else{ // near big
if(t_ratio == 3){
tmp_big = big - sma;
// like IV
cal_char[ base_char[big_pos] - 'A' ] ++;
cal_char[ base_char[sma_pos] - 'A' ] ++;
// cout<< base_char[sma_pos]<< base_char[big_pos];
}else{
tmp_big = big - base_num[sma_pos-1];
// like IX
cal_char[ base_char[big_pos] - 'A' ] ++;
cal_char[ base_char[sma_pos-1] - 'A' ] ++;
// cout<< base_char[sma_pos-1]<< base_char[big_pos];
}
num -= tmp_big;
}
}
return;
}
int main(void){
// freopen("preface.out","w",stdout);
// freopen("preface.in","r",stdin);
cin>>n;
for(int i=1;i<=n;i++){
//cout<<i<<":";
pr(i);
//cout<<endl;
}
int cal;
for(int j=0;j<7;j++){
cal=cal_char[base_char[j] - 'A'];
if( cal > 0 ){
cout<<base_char[j]<<" "<<cal<<endl;
}
}
return 0;
}