51Nod - 1385 凑数字(思维)

给定一个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

多写几个样例,发现每次加数字都可以加在最后面,比如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;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值