HDU 3652 B-number(数位)

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;

int a[15];
//dp[i][j][k]
//i:数位
//j:余数
//k:3种操作状况,0:末尾不是1,   1:末尾是1,    2:含有13
int dp[15][15][3];

int dfs(int pos, int mod, int st, int limit) { //lim记录上限

    if(pos == -1)
        return mod == 0 && st == 2;

    if(!limit && dp[pos][mod][st] != -1)//没有上限并且已被访问过
        return dp[pos][mod][st];

    int up = limit ? a[pos] : 9;//假设该位是2,下一位是3,如果现在算到该位为1,那么下一位是能取到9的,如果该位为2,下一位只能取到3
    int ans = 0;

    //需要在记忆化搜索中增加一个参数mod即可,利用(a * b) % mod = (a % mod) * (b % mod)和(a + b) % mod = (a % mod) + (b % mod)来计算.比如说73 % 10 = ((7 % 10) * 10 + 3) % 10,
    for(int i = 0; i <= up; i++) {
        int mod_x = (mod * 10 + i) % 13;//难点:数学公式
        if(st == 2 || (st == 1 && i == 3)) {
            ans += dfs(pos-1, mod_x, 2, limit && i == up);
        } else if(i == 1) {
            ans += dfs(pos-1, mod_x, 1, limit && i == up);
        } else {
            ans += dfs(pos-1, mod_x, 0, limit && i == up);
        }
    }

    if(!limit)
        dp[pos][mod][st] = ans;

    return ans;
}

int main() {
    int n, len;
    while(~scanf("%d", &n)) {
        memset(a, 0, sizeof(a));
        memset(dp, -1, sizeof(dp));
        len = 0;

        while(n) {
            a[len++] = n%10;
            n /= 10;
        }

        printf("%d\n", dfs(len-1, 0, 0, 1));
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/ccshijtgc/article/details/82529328