HDU - 3652 B-number(数位dp详解)

数位dp  至少要会两个基础题目,再做这道题才较容易。

https://cn.vjudge.net/problem/CodeForces-55D   (kuangbin数位dp  A题)(*推荐看这道题的博客时,思路不用完全看懂,还是代码好懂一点*)

https://blog.csdn.net/wust_zzwh/article/details/52100392   (kuangbin数位dp  C题)数位dp入门(不要62)推荐,剩下的进阶版实在是本人能力有限,看不太懂,还是一步一步刷专题吧。以后再看。

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.
InputProcess till EOF. In each line, there is one positive integer n(1 <= n <= 1000000000).OutputPrint each answer in a single line.Sample Input
13
100
200
1000
Sample Output
1
1
2
2

题意:一个wqb数字或简称B数字是一个非负整数,其十进制形式包含子串“13”,并且可以除以13.例如,130和2613是wqb数字,但是143和 2639不是。 您的任务是计算给定整数n中从1到n有多少个wqb数字。
我的感受:做完这道题感觉数位dp才懂了点皮毛。

思路:有两个条件包含13,并且是13的倍数。那么怎么同时控制两个条件呢,

int dp[pos][sta][num];  pos表示位数,if(sta==0)表示上一位不是1,if(sta==1)表示上一位是1,if(sta==2)表示出现13字符串,num表示%13之后的数字。

#include 
#include 
#include 
#include 
#include 
#include 
#define mem(a,b) memset(a,b,sizeof(a))
#define inf 0x3f3f3f3f
typedef long long LL;
const LL mod=1e9+7;
const int M=13;
using namespace std;
const int N =1e5+100;
int dp[15][3][15];//dp[pos][str][num];
int a[15];
int gett(int str,int i)
{
    if(str==0)//上一位不是1
    {
        if(i==1) return 1;//若这位为1,则return 1;
        else return 0;//若这位不是1 ,则return 0;
    }
    else if(str==1)//上一位为1;
    {
        if(i==1) return 1;//若这位为1,则return 1;
        if(i==3) return 2;//若这位为3,则return 2;
        return 0;//否则,return 0;
    }
    return 2;//出现过13,则 return 2;
}
int dfs(int pos,int str,int num,int limit)//其他地方就是数位dp板子了
{
    if(pos==-1) return num==0&&str==2;//**(重点)**题目有两个条件,num%13==0并且str==2(包含13);这样的数字才计数。
    if(!limit&&~dp[pos][str][num]) return dp[pos][str][num];
    int up=limit?a[pos]:9,ans=0;
    for(int i=0; i<=up; i++)
            ans+=dfs(pos-1,gett(str,i),(num*10+i)%M,limit&&i==up);//str的改变在gett函数中
    return limit?ans:dp[pos][str][num]=ans;
}
int slove(int x)
{
    int pos=0;
    while(x)
    {
        a[pos++] =x%10;
        x/=10;
    }
    return dfs(pos-1,0,0,1);
}
int main()
{
    int n;
    mem(dp,-1);
    while(~scanf("%d",&n))
        printf("%d\n",slove(n));
}



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