HDU3652:B-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
 
 
题意:给你一个数n,找出1~n之间有几个数能被13整除而且含有13。
 
dp[len][mod][have],len表示当前的位数,mod表示上一位mod 13 的余数,have = 1表示前一位取1,have = 2表示出现过“13”。
思路就是记忆化搜索设置参数flag表示接下来的数是否一定比给的数小。
 
 
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
ll dp[30][20][3];
ll a[30];
ll dfs(int len , int mod , int have , int flag) {
    if(len == 0) {
        return have == 2 && mod == 0;
    }
    if(!flag && dp[len][mod][have] != -1) {
        return dp[len][mod][have];
    }
    int t = flag ? a[len] : 9;
    ll sum = 0;
    for(int i = 0 ; i <= t ; i++) {
        if(have == 0 && i == 1) {
            sum += dfs(len - 1 , (mod * 10 + i) % 13 , 1 , flag && i == t);
        }
        else if(have == 1 && i == 3) {
            sum += dfs(len - 1 , (mod * 10 + i) % 13 , 2 , flag && i == t);
        }
        else if(have == 1 && i != 1) {
            sum += dfs(len - 1 , (mod * 10 + i) % 13 , 0 , flag && i == t);
        }
        else {
            sum += dfs(len - 1 , (mod * 10 + i) % 13 , have , flag && i == t);
        }
    }
    if(!flag)
        dp[len][mod][have] = sum;
    return sum;
}
ll Get(ll x) {
    ll gg = x;
    memset(dp , -1 , sizeof(dp));
    memset(a , 0 , sizeof(a));
    int len = 0;
    while(gg) {
        a[++len] = gg % 10;
        gg /= 10;
    }
    return dfs(len , 0 , 0 , 1);
}
int main()
{
    ll n;
    while(cin >> n){
        cout << Get(n) << endl;
    }
    return 0;
}
原文地址:https://www.cnblogs.com/TnT2333333/p/6007760.html