number HDU - 3652 (数位DP)

number

HDU - 3652

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

这是我自己做出的第一道数位DP题

题意:要求数字含有13并且被13整除,所以需要传入每次mod13的结果看最后是否mod13==0,而且每次传入前一位如果前一位是1,并且当前位是3,状态state为1,并且如果状态state为1后之后全是1,最后当状态为1(含有13)并且mod13为0时返回1

我当时wa了好多次,以为dp数组没有记录状态state这一项,因为当时想如果可以满足条件最后的state不应该都是1吗,就没记录,但实际上state的记录最多只能记录到倒数第二位,也就是传进来的state是没有枚举这一位之前数的state,那么当我们枚举最后一位的时候就有可能存在这种情况,之前state全是0.而之前数字最后一位是1,现在你又枚举了3,继续递归发现到最后了,返回上一层递归,这时候储存记录下来的是state为0的情况,所以state应该记录

网上写的我看状态都分了三种,感觉没有必要

code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef __int64 ll;
int digit[25];
ll dp[25][10][20][2];
ll dfs(int pos,int pre,int num,int yes,int limit){
    if(pos == -1)
        return yes && num % 13 == 0;
    ll &dpnow = dp[pos][pre][num][yes];
    if(!limit && dpnow != -1)
        return dpnow;
    int max_digit = limit ? digit[pos] : 9;
    ll ans = 0;
    for(int i = 0; i <= max_digit; i++){
        if(yes){
            ans += dfs(pos - 1, i, (num * 10 + i) % 13, 1, limit && i == max_digit);
        }
        else{
            ans += dfs(pos - 1, i, (num * 10 + i) % 13, pre == 1 && i == 3, limit && i == max_digit);
        }
    }
    if(!limit)
        dpnow = ans;
    return ans;
}
ll solve(ll n){
    int pos = 0;
    while(n){
        digit[pos++] = n % 10;
        n /= 10;
    }
    return dfs(pos-1,0,0,0,1);
}
int main(){
    ll n;
    memset(dp,-1,sizeof(dp));
    while(cin >> n){
        cout << solve(n) << endl;
    }
    return 0;
}



猜你喜欢

转载自blog.csdn.net/codeswarrior/article/details/80438792