1385 凑数字
给定一个n,要求找出一个最短的字符串S,使得所有1到n的整数都是S的子序列。
比如n=10,那么S=”1234056789”的时候,是满足条件的。这个时候S的长度是10。
现在给出一个n,要求输出最短S的长度。
第1行:给出一个整数n (1<=n<=1e10000)。
输出最短S的长度
10
10
题解:orz真是强无敌。。。
f(n)表示最短S的长度。
那么首先f(n)>=f(n-1),这是为什么呢?
反证法,假如f(n)<f(n-1)那么f(n)的时候他的S是可以表示1到n-1的所有数字的,那么f(n-1)明显可以取到f(n)的,所以与f(n-1)是最小值矛盾,f(n)>=f(n-1).
f(n)的时候可以表示1到n的数字。那么在这个串中每一种数字至少要有len(n)-1个。
Len(n)表示n的十进制长度。
而每一种数字在1到n中出现次数最多的可能是len(n).
最后答案是每一种数字在1到n中出现次数最多的加起来。
下面证明一下,
构造串的时候可以这样构造,先每一种数字拿出len(n)-1个,然后按照以下顺序排列
9876543210*(len(n)-1).
那么剩下的数字记为R就放在开头。这个时候对于以剩下数字开头的数字且长度==len(n)的是非常好表示的。但是那些开头不在R里面的怎么办呢?
这个时候要表示的数字的形状是这样的子的
先找到最小的k,使得前面k位相等,然后到k+1位,b(k+1)<b(k)
所以这儿第k堆的9876543210里面有两个或以上的数字可以利用了。
这样也是能够构造出len(n)长度的数字。
为什么这样是最少的呢?
这个是因为串中每一种数字出现的次数是取1到n中出现次数最多,如果某个数字少一个,肯定表示不了其中一个数字。所以是最少的。
总的计算复杂度是O(len(n))
代码:
#include<bits/stdc++.h>
using namespace std;
int m,i,j,ans,a[100002],p;
char s[100002];
int main(){
scanf("%s",&s);
m=strlen(s);
for(i=0;i<m;i++)
a[i+1]=s[i]-'0';
for(i=9;i;i--){
p=0;
for(j=1;j<=m;j++)
{
if(a[j]<i){
p=1;
break;}
if(a[j]>i){
break;
}
}
if(!p){
ans=i;
break;
}
}
printf("%d",ans+(m-1)*10);
}