USACO 2.2.1 序言页码 Preface Numbering

题解

这道有点意思,本来很快写完的,被一个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;
}

猜你喜欢

转载自blog.csdn.net/smmyy022/article/details/81479070