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
,后三位共需长度为
首先考虑 2221 :乍一看,会向串首加入字符 ‘2’ 和 ‘1’。但观察后可以发现,只需要在串首添加字符 ‘2’,将字符串长度增至 31 即可完整表达 2221 。因为数字 1111 可通过重用 str 中区间为 [1,10] 的字符来表达。
可是,这种规律在数字 2222 上不成立。因为长为 30 的由三个“1234567890”构成字符串只包含三个 ‘1’,我们无法用它来表达数字 1111 。这时,就需要将字符 ‘2’ 和 ‘1’ 同时添加至串首。
再看数字 2322 :与 2222 同理,这时也应该将字符 ‘2’ 和 ‘1’ 同时加至串首。
现在可以将上述规律推广到一般情况:
设给定的数字位数为
d
, 表达它所需的字符串长度为
#include <string>
#include <iostream>
#include <algorithm>
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;
}