hdu 4389 X mod f(x) (数位dp)

原题地址:http://acm.hdu.edu.cn/showproblem.php?pid=4389
思路:dp[pos][mod][d][sum]表示前i位数除以d得到余数mod且此时前i位和为sum的数字的个数,这里d在1~81范围内枚举,递归的边界是恰好满足d == sum且mod % sum == 0,最后累加所有的情况即可(枚举d)

很明显,如果直接枚举的话,你每次的模数都会在改变,因此难以下手。所以我们可以换一种思路,先假设定一个固定的模数(范围只有0-81,因此可以枚举),然后最后改成判断是不是合法的就行了。

#include <bits/stdc++.h>
const int INF = 0x7F7F7F7F;
const int MOD = 1e9 + 7;
const double EPS = 1e-10;
const int maxn = 1e5 + 6666;
//这题就是假设了所有的的和的情况,然枚举每一位,判断是不是最后的合法
int dp[12][83][83][83], a[66];
//dp[pos][mod][d][sum]表示前i位数除以d得到余数mod且此时前i位和为sum的数字的个数,
//这里d在1~81范围内枚举,递归的边界是恰好满足d == sum且mod % sum == 0,
//最后累加所有的情况即可(枚举d)
int dfs (int pos, int mod, int d, int sum, bool limit) {
    if (pos == 0) return (d == sum && mod % d == 0);
    if (!limit && dp[pos][mod][d][sum] != -1) return dp[pos][mod][d][sum];
    int res = 0;
    int up = limit ? a[pos] : 9;
    for (int i = 0; i <= up; i++) {
        int tt = (mod * 10 + i) % d;
        res += dfs (pos - 1, tt, d, sum + i, limit&&i==up);
    }
    if(!limit) dp[pos][mod][d][sum] = res;
    return  res;
}

int solve (int x) {
    int cnt = 0;
    while (x) {
        a[++cnt] = x % 10;
       x /= 10;
    }

    int res = 0;
    for (int i = 1; i <= 81; i++)
        res += dfs (cnt, 0, i, 0, 1);
    return res;
}

int main() {
    memset (dp, -1, sizeof (dp));
    int t, id = 1;
    scanf ("%d", &t);
    while (t--) {
        int vala, valb;
        scanf ("%d%d", &vala, &valb);
        printf ("Case %d: %d\n", id++, solve (valb) - solve (vala - 1));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81106782
今日推荐