给定一个n,要求找出一个最短的字符串S,使得所有1到n的整数都是S的子序列。
比如n=10,那么S=”1234056789”的时候,是满足条件的。这个时候S的长度是10。
现在给出一个n,要求输出最短S的长度。
Input10
10
多写几个样例,发现每次加数字都可以加在最后面,比如10这个数,现在是{1,2,3,4,5,6,7,8,9,0}长度为10,而11的时候必须要加一个1才能满足条件,此时字符串长度为11,而12的时候在11的基础上不需要加数,因为11已经有{1,2}这个子串了,这样一直持续到21的时候都不需要加数字,而到了22的时候,和11一样,必须要加一个2才能满足条件,而接下来23、24、一直到32都是在22的基础上不要加数字的,到了33才需要加个3
于是可以得出规律,当所有位的数字相同时需要才加一个数
所以我们只要遍历输入的字符串的每一位的数就OK了,拿这个数与第一位进行比较(因为如果要加的话得保证每一位都不小于第一位)
而之前还有个工作就是打表,因为很容易就可以看出来,比如13是个两位数,那么它至少需要一组{1,2,3,4,5,6,7,8,9,0},比如113,那么它就需要两组{1,2,3,4,5,6,7,8,9,0},所以n位数至少需要n-1组{1,2,3,4,5,6,7,8,9,0},于是就先打个表为快
代码
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char n[10005];
int num[10005];
void f()
{
for(int i=2;i<=10003;i++)
num[i]=(i-1)*10;
}
int main()
{
f();
while(~scanf("%s",n))
{
int len=strlen(n);
if(len==1)
printf("%d\n",n[len-1]-'0');
else if(len==2&&n[0]=='1'&&n[1]=='0')
printf("10\n");
else
{
int cnt=0;
int i;
for(i=1;i<len;i++)
if(n[i]>n[0]) //每一位都与第一位进行比较,大于的话就说明肯定已经覆盖了所有位数相等的情况
{
cnt=n[0]-'1'+1;
break; //所以就可以break了
}
else if(n[i]<n[0]) //小于的话肯定就覆盖不到了
break;
if(!cnt&&i<len) //如果没覆盖到,那么加上首位数减一,因为它虽然覆盖不了所有位置跟自己相等的那个数,但它肯定可以覆盖比
cnt=n[0]-'1'; //它小一的数的那个全覆盖了的数嘛(真绕口)
else if(i==len&&!cnt)
cnt=n[0]-'1'+1; //既然恰好覆盖,那就不多说了
printf("%d\n",cnt+num[len]); //打表大法好
}
}
return 0;
}