不要62 (数位dp,函数内外定义数组的初始值

     杭州人称那些傻乎乎粘嗒嗒的人为62(音:laoer)。
    杭州交通管理局经常会扩充一些的士车牌照,新近出来一个好消息,以后上牌照,不再含有不吉利的数字了,这样一来,就可以消除个别的士司机和乘客的心理障碍,更安全地服务大众。
    不吉利的数字为所有含有4或62的号码。例如:
    62315 73418 88914
    都属于不吉利号码。但是,61152虽然含有6和2,但不是62连号,所以不属于不吉利数字之列。
    你的任务是,对于每次给出的一个牌照区间号,推断出交管局今次又要实际上给多少辆新的士车上牌照了。
Input
    输入的都是整数对n、m(0<n≤m<1000000),如果遇到都是0的整数对,则输入结束。
Output
    对于每个整数对,输出一个不含有不吉利数字的统计个数,该数值占一行位置。
Sample Input

    1 100
    0 0

Sample Output

    80

枚举肯定是不行的 ,数位太多 ,会超时

所以用dp递推出以i为首位,位数为j的数字个数dp[i][j]并储存,以空间降低时间

递推过程,高位dp为低位各dp的和,并判断4和62的情况

for (int j=1; j<=9; j++){
        for (int i=0; i<=9; i++){
            if (j==1) dp[i][j]=1;
            if (i==4) dp[i][j]=0;
            else if(i==6){
               dp[i][j]=dp[i][j]+dp[0][j-1]+dp[1][j-1];    
               for (int k=3;k<=9;k++)dp[i][j]+=dp[k][j-1];    
            }
            else for (int k=0;k<=9;k++)dp[i][j]+=dp[k][j-1];
        }
    }

或 更简单的

(在函数外定义dp[10][10])

    dp[0][0] = 1;

    for (int i = 1; i <= 7; ++i)
        for (int j = 0; j <= 9; ++j)
            for (int k = 0; k <= 9; ++k) {
                if (j != 4 && !(j == 6 && k == 2))
                    dp[i][j] += dp[i - 1][k];

注:g++环境下 在函数外定义数组初始值是0,在函数内定义数组初始值是随机值

 

求出0~n和0~m+1之间的数位,相减即是n~m之间的数位个数

数位统计函数:

long long solve(int x){
    int a[10]={0},k,i=0;
    long long ans=0;
    while(x){
        a[++i]=x%10;
        x/=10;
    }
    for (int j=i;j>=1;j--){
        for (int k=0;k<a[j];k++){
            if (!( k==2&&a[j+1]==6))
            ans+=dp[k][j];
//            printf("i %d  j %d %lld\n",k,j,dp[k][j]);
        }
        if(a[j]==4||a[j]==2&&a[j+1]==6)break;
    }
//    printf("%d-%lld\n",x,ans);
    return ans;
}

(因为随机值的问题,刚开始没有写a【10】={0},结果a【4】正好随机为6)

#include<bits/stdc++.h>
#define ll long long
using namespace std;

ll dp[10][10];
long long solve(int x){
    int a[10]={0},k,i=0;
    long long ans=0;
    while(x){
        a[++i]=x%10;
        x/=10;
    }
    for (int j=i;j>=1;j--){
        for (int k=0;k<a[j];k++){
            if (!( k==2&&a[j+1]==6))
            ans+=dp[k][j];
//            printf("i %d  j %d %lld\n",k,j,dp[k][j]);
        }
        if(a[j]==4||a[j]==2&&a[j+1]==6)break;
    }
//    printf("%d-%lld\n",x,ans);
    return ans;
}

int main(){
//   freopen("input.txt","r",stdin);
//   freopen("output.txt","w",stdout);
    memset(dp,0,sizeof(dp));
    //num-dig dp
    for (int j=1; j<=9; j++){
        for (int i=0; i<=9; i++){
            //1-dig num
            if (j==1) dp[i][j]=1;
            if (i==4) dp[i][j]=0;
            else if(i==6){
               dp[i][j]=dp[i][j]+dp[0][j-1]+dp[1][j-1];    
               for (int k=3;k<=9;k++)dp[i][j]+=dp[k][j-1];    
            }
            else for (int k=0;k<=9;k++)dp[i][j]+=dp[k][j-1];
//            printf("dp %d %d  %lld\n",i ,j ,dp[i][j]);
        }
    }
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF&&(m||n)){
        printf("%lld\n",solve(m+1)-solve(n));
    }
    return 0;
}
posted @ 2019-01-27 15:19  易如鱼  阅读(268)  评论(0编辑  收藏  举报