HDU 3652(数位DP)

题目链接:B-number

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 4911    Accepted Submission(s): 2816


Problem Description
A wqb-number, or B-number for short, is a non-negative integer whose decimal form contains the sub- string "13" and can be divided by 13. For example, 130 and 2613 are wqb-numbers, but 143 and 2639 are not. Your task is to calculate how many wqb-numbers from 1 to n for a given integer n.
 
Input
Process till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).
 
Output
Print each answer in a single line.
 
Sample Input
13 100 200 1000
 
Sample Output
1 1 2 2
 
Author
wqb0039
 

 今天艾教讲了数位DP,自己硬着头皮写,竟然AC了,开心。

数位DP,dp[i][k]这两维是当前枚举到i,k是与给定的数比较,如果前i个数,正好等于给定的数,那么就是k就是1,否则就是0.举个栗子,比如给的最大的是236789.现在枚举到第三位6,如果前两个数是23,那么k=1,否则等于0.   然后对于本题还需两维,一维表示余数0-12,一维表示前面是否有13   d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0) d =2表示前面已经有13了,d=1表示前面只有1,0表示其他。

初始化dp[0][0][1][0] = 1,对于这个,晚上我和翔哥讨论了一下午,为什么初始化这个dp[0][0][1][0],或者为什么初始化1.最后对所有dp[n]的数求和,比如给的数是1300,那么求和后得到是1301,数位dp把1300分成了许多集合,满足这个条件的在一个集合,满足那个条件的在那个集合。为什么多一,翔哥自己迷迷糊糊的在分析,我也听的迷迷糊糊,如果有大神路过,希望留下解释,谢谢!

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int mod = 13;
int dp[15][15][3][4];
char s[20];
int mi[15];
int cal(int x,int wei,int p)
{
    return x*mi[wei]%p;
}
int main()
{
    mi[0]=1;
    for (int i=1;i<=13;i++)
        mi[i]=mi[i-1]*10%13;
    while(scanf("%s",s)!=EOF)
    {
        int n = strlen(s);
        memset(dp,0,sizeof(dp));
        dp[0][0][1][0] = 1;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<=12;j++)
            {
                for(int k=0;k<=1;k++)
                {
                   for(int d=0;d<=2;d++)
                   {
                       if(dp[i][j][k][d]!=0)
                       {
                           int l = 0;
                           int r = (k==1)?s[i]-'0':9;
                           for(int p=l;p<=r;p++)
                           {
                               dp[i+1][(j+cal(p,n-i-1,13))%13][(k==1&&p==r)?1:0][d==2?(2):((d==1&&p==3)?2:(((d==1||d==0)&&p==1)?1:0))]
                               += dp[i][j][k][d];
                           /*    if((i+1==4&&(j+cal(p,n-i-1,13))%13==0&&((k==1&&p==r)?1:0)==1&&(d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0)))==2)||(i+1==4 && (j+cal(p,n-i-1,13))%13==0 && ((k==1&&p==r)?1:0==0) &&(d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0)))==2))
                               printf("dp[%d][%d][%d][%d] = %d
",i+1,(j+cal(p,n-i-1,13))%13,(k==1&&p==r)?1:0,d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0)),dp[i+1][(j+cal(p,n-i-1,13))%13][(k==1&&p==r)?1:0][d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0))]);*/
                           //     printf("%d dp[%d][%d][%d][%d] = %d    dp[%d][%d][%d][%d] = %d
", p,i,j,k,d,dp[i][j][k][d],i+1,(j+cal(p,n-i-1,13))%13,(k==1&&p==r)?1:0,d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0)),dp[i+1][(j+cal(p,n-i-1,13))%13][(k==1&&p==r)?1:0][d==2?(2):((d==1&&p==3)?2:((d==0&&p==1)?1:0))]);//*/

                           }
                       }
                   }
                }
            }
        }
     /*   int ans = 0;
        for(int i = 0; i < 13; i ++)
            for(int j = 0; j < 2; j++)
                for(int k = 0; k < 3; k++)
                    ans+=dp[n][i][j][k];*/
        printf("%d
",dp[n][0][1][2]+dp[n][0][0][2]);
        //printf("%d
",ans);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/littlepear/p/5747763.html