1. 程式人生 > >HDU 3652 B-number(數位)

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;
}