nyist oj 1172 unlucky number

来源:互联网 发布:乐秀软件下载 编辑:程序博客网 时间:2024/06/07 05:11

unlucky number

时间限制:1000 ms  |  内存限制:65535 KB
难度:0
描述
我们定义在区间【l,r】之间只出现1和7组合的数是unlucky number,例如:1 、7、 11、17 都是unlucky numbers ,而 13 、27则不是,问在区间【l,r】内有多少 unlucky numbers??
输入
有多组测试数据(不超过100组)
每组输入两个整数l,r( 0 =< l<= r <= 10^18)
输出
每行输入一个结果
样例输入
1 7
样例输出
2

假设有两个数组a[n]和b[n],a[i]表示i位数中共有多少种1和7的组合,我们看看怎么求a[i],首先看第一位,有两种选择(1和7),再看第二位,有两种选择,依次进行,每一位都是两种选择,根据分步乘法计数原理,a[i]=2^i。

b[i]表示1~10^i之间共有多少种1和7的组合,显然b[i]=a[1]+a[2]+a[3]+……a[i]=2^(i+1)-2,即b[i]=(b[i-1]+2)*2-2。

如果计算l~r之间的1和7的组合数,假设某函数f(n)可以计算1~n之间的组合数,则结果等于f(r)-f(l-1),但是如果l是一个字符串的大数的话,还要计算大数减法,为了避免这种情况,可以计算f(r)-f(l),然后如果l是1和7的组合的话,再加上1就行了,简单了许多。

那么如何计算任意一个数的符合条件的数的数目,比如8817,首先在1~1000之内有b[3]个数,然后当千位分别是1和7时,都有a[3]个数,所以是2*a[3],所以总共的情况有b[3]+2*a[3]=30,但是只有这么简单吗,是的,在这个情况下,他只需要O(1)的复杂度,但对于最坏的情况,比如7720,首先在1~1000之内有b[3]个数,然后当千位分别是1时,有a[3]个数,所以是a[3],当千位是7时,他的具体数目要往后面看,看百位是7,当是1时,有了a[2]种可能,当成为7时,还要往后看,十位是2,此时当十位是1时,包含了所有情况,即只有a[1],即所有的可能为b[3]+a[3]+a[2]+a[1]=28。基于此思想,可以形成最坏O(N)复杂度的算法,其中n为字符串的长度,所以此计数不只是局限于long long 内,以下是代码,仅供参考

 #include <cstdio>#include <cstring>int dp[24];int cau(char *s){    int len=strlen(s),sum,num,flag;    sum=dp[len-1];flag=1;    for(int i=0;i<len-1;i++){        num=s[i]-'0';        if(num==0)  break;        if(num==1)  {if(i==len-2)   flag=0;continue;}        if(num<7)  {sum+=dp[len-1-i]-dp[len-2-i];break;}        if(num==7)   {sum+=dp[len-1-i]-dp[len-2-i];if(i==len-2) flag=0;continue;}        sum+=dp[len-1-i]-dp[len-2-i]+dp[len-1-i]-dp[len-2-i];break;    }    if(flag&&len>1)   return sum;    num=s[len-1]-'0';    if(num<1)   return sum;    if(num<7)   return sum+1;                return sum+2;}char h1[24],h2[24];int main(){    dp[1]=2;dp[2]=6;    for(int i=3;i<=24;i++) dp[i]=(dp[i-1]+2)*2-2;    while(scanf("%s%s",h1,h2)!=EOF){        int j=1,len=strlen(h1);        for(int i=0;i<len;i++){            if(h1[i]=='1'||h1[i]=='7')  continue;            j=0;break;        }        printf("%d\n",cau(h2)-cau(h1)+j);    }    return 0;}        

以上代码中,dp数组就是代表b数组,h2和h1字符串分别表示r和l这两个数。cau()就是以上说的f()函数。

这个代码还可以再写短一点,让它更美观,不过这不是问题的主要矛盾,还有一个问题,这个cau函数真的能计算任意长度的数字吗,其实,最好的情况下,在计算cau(n)时,当n=10^31时,就会有2^32-2种可能,超出了int的范围,就算把cau()的返回值设为long long,那么n=10^63时,会超出范围,所以这个代码是不完美的,但可以修正,只要把cau()函数的返回值改为字符串,其中的加法改为大数加法就行了,就可以支持任意有限位的整数。
0 0
原创粉丝点击