HDU-3562-B-number(数位DP)

B-number

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

解题思路:

数位DP。
对于第一个限制出现13 枚举时区分三种状态:
1、前面已经出现过13 记为状态2
2、前面没出现13但前一位是1 记为状态1
3、前面没出现13且前一位不是1 记为状态0
对于第二个限制,在枚举每一位的时候对上一位留下来的数乘10+i再取模,这个想了好久,有一个定理证明的。但是我没想那么多,也就写了几个数发现好像是这样就写了,结果就过了。。

AC代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#define int long long
using namespace std;
int a[20];
int dp[20][20][5];

int dfs(int pos,int pre,int sta,int limit,int flag)
{
    if(pos == -1) return (flag == 2 && sta == 0);
    if(!limit && dp[pos][sta][flag] != -1) return dp[pos][sta][flag];
    int up = limit ? a[pos] : 9;
    int tmp = 0;
    for(int i = 0 ;i <= up ; i ++)
    {
        tmp += dfs(pos-1,i,(sta*10+i)%13,limit && a[pos] == i ,
                (flag == 2 ? 2 : ((pre == 1 && i == 3) ? 2 : (i == 1 ? 1 : 0) )  ));
    }
    if(!limit) dp[pos][sta][flag] = tmp;
    return tmp;
}

int solve(int x)
{
    int pos = 0;
    while(x)
    {
        a[pos++] = x%10;
        x /= 10;
    }
    return dfs(pos-1,0,0,1,0);
}

signed main()
{
    int n,a,b;
    memset(dp,-1,sizeof(dp));
    while(cin>>n)
        cout<<solve(n)<<endl;
    return 0;
}

发布了104 篇原创文章 · 获赞 7 · 访问量 4083

猜你喜欢

转载自blog.csdn.net/qq_43461168/article/details/103330437