CSU-ACM2017暑假集训比赛7 - F - 凑数字 - 51Nod - 1385

F - 凑数字

给定一个n,要求找出一个最短的字符串S,使得所有1到n的整数都是S的子序列。

比如n=10,那么S=”1234056789”的时候,是满足条件的。这个时候S的长度是10。



现在给出一个n,要求输出最短S的长度。

Input

第1行:给出一个整数n (1<=n<=1e10000)。

Output

输出最短S的长度

Sample Input

10

Sample Output

10

首先一定要明确“子序列”的意义,然后就容易想到,将一个数的位数减一,得到的就是表达除最高位外所有低位数字所需要的字符串“1234567890”的个数。

重要的是最高位如何处理。举一组例子:取四位数 2221 2222 2322 。首先知道,若不考虑最高位的 2 ,后三位共需长度为 30 的字符串 str 来表达。现在需要在字符串的首部加入若干字符,从而使得字符串可以表达完整的四位数。

首先考虑 2221 :乍一看,会向串首加入字符 ‘2’ 和 ‘1’。但观察后可以发现,只需要在串首添加字符 ‘2’,将字符串长度增至 31 即可完整表达 2221 。因为数字 1111 可通过重用 str 中区间为 [1,10] 的字符来表达。

可是,这种规律在数字 2222 上不成立。因为长为 30 的由三个“1234567890”构成字符串只包含三个 ‘1’,我们无法用它来表达数字 1111 。这时,就需要将字符 ‘2’ 和 ‘1’ 同时添加至串首。

再看数字 2322 :与 2222 同理,这时也应该将字符 ‘2’ 和 ‘1’ 同时加至串首。

现在可以将上述规律推广到一般情况:
设给定的数字位数为 d , 表达它所需的字符串长度为 len 。首先令 len=10×(d1) ,然后从给定数字的最高位出发走向最低位,将途中遇到的第一个与最高位不同的个数字 k 与最高位数字 n 比较,若 k<n ,则执行 len=len+n1 操作;若 k>n ,或者找不到任何 kn ,则执行 len=len+n 操作。这样得到的字符串 str 拥有足够表达给定数字的最短长度。

#include 
#include 
#include 
using namespace std;

int main(){
#ifdef TEST
freopen("test.txt", "r", stdin);
#endif // TEST

    string sample;
    while(cin >> sample){
        int cnt = 0, len = sample.length();
        cnt += (len - 1)*10;
        cnt += sample[0]-'1';
        bool add = true;
        for(int i = 1; i < len; i++){
            if(sample[i] < sample[i-1]){
                add = false;
                break;
            }
            else if(sample[i] > sample[i-1])
                break;
        }
        if(add)
            cnt++;
        cout << cnt << endl;
    }

    return 0;
}

你可能感兴趣的:(CSU-ACM2017暑期训练,模拟)