hdu3652B-number (数位dp)

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
 


题意:给你一个数n,让你求1~n中有多少数x符合x%13==0 且x中出现过“13”这个子串。

思路:用dfs(pre,pos,num,flag,limit)来数出所有符合条件的数,其中pre表示这一位的上一位是什么,pos表示当前正循环到哪个位置,num表示到这一位时的总和(%13后,且这一位还没有算),flag表示之前的字符串中是否已经出现过"13"这个字符串,limit表示当前这位是有限制还是没有限制的,有限制的话,这一位最高遍历到wei[pos],没有限制的话最高遍历到9.另外没有剪枝的话会超时,所以用dp[pre][pos][num][flag]表示在limit==0的情况下,后面可以加上的值,如果(pre,pos,flag)这个状态已经遍历过的话,就不用遍历一遍了。


#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<string>
#include<bitset>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef long double ldb;
#define inf 99999999
#define pi acos(-1.0)
#define maxn 805
int wei[15];
int dp[11][40][15][2];//到i位置%13为j且是否含有13的flag值为k的方案数

int dfs(int pre,int pos,int num,int flag,int limit){
    int i,j;
    if(pos==0){
        if((num%13==0) && (flag==1))return 1;
        return 0;
    }
    if((limit==0) && (dp[pre][pos][num][flag]!=-1) ){
        return dp[pre][pos][num][flag];
    }

    int sum=0;
    int num1,flag1;

    if(limit==0){
        for(j=0;j<=9;j++){
            num1=(num*10+j)%13;
            flag1=flag;
            if((pre==1) && (j==3) ){
                flag1=1;
            }
            sum+=dfs(j,pos-1,num1,flag1,0);
        }
    }
    else if(limit==1){
        for(j=0;j<=wei[pos];j++){
            num1=(num*10+j)%13;
            flag1=flag;
            if((pre==1) && (j==3) ){
                flag1=1;
            }
            if(j<wei[pos])sum+=dfs(j,pos-1,num1,flag1,0);
            else sum+=dfs(j,pos-1,num1,flag1,1);
        }
    }

    if(limit==0){
        dp[pre][pos][num][flag]=sum;
    }
    return sum;
}
int solve(int x)
{
    int i,j,len=0,t=x;
    while(t){
        wei[++len]=t%10;
        t/=10;
    }
    wei[len+1]=0;
    memset(dp,-1,sizeof(dp));
    int sum;
    sum=dfs(0,len,0,0,1);
    return sum;
}


int main()
{
    int n,m,i,j;
    while(scanf("%d",&n)!=EOF)
    {
        printf("%d\n",solve(n));
    }
}


你可能感兴趣的:(数位dp)