Codeforces - 95D. Horse Races - 数位dp+大数运算

Horse Races

题目链接

分类dp math

1.题意概述

  • 规定47是幸运数,而且约定一个数是“辛运数字”当且仅当,相邻两个幸运数字的数位距离不超过 k(1k1000) ,现在给定你一个区间 [l,r](1lr101000) ,问你这个区间的幸运数字有多少个,答案取模 109+7

2.解题思路

  • 很显然,这是一道数位dp的题目,两个难点,一个在于大数如何转化,第二个在于如何统计不超过k的距离,第一个我们可以通过读入字符串,然后将字符串倒序就可以实现,但是因为我们是统计的前缀,因此在 l1 时候模拟大数减法不要忘了可能会出现退位现象。而第二个难点,我们可以直接考虑在dfs时候增加一个限制条件看距离上一个距离是否小于 k 即可,细节很多,参见代码:

3.AC代码

int digit[N];
ll dp[N][N][2];
char l[N], r[N];
int k;
int dfs(int len, int p, bool flag, bool limit) {
    if (len == 0) return flag;
    if (limit == 0 && dp[len][p][flag] != -1) return dp[len][p][flag];
    int up = limit ? digit[len] : 9;
    int res = 0;
    rep(i, 0, up + 1) {
        if (i != 4 && i != 7)
            res = (res + dfs(len - 1, max(0, p - 1), flag, limit && i == up)) % mod;
        else res = (res + dfs(len - 1, 1 * k, flag || p, limit && i == up)) % mod;
    }
    if (!limit) dp[len][p][flag] = res;
    return res;
}
inline void solve() {
    int t;
    memset(dp, -1, sizeof dp);
    scanf("%d%d", &t, &k);
    while (t--) {
        scanf("%s%s", l, r);
        int len = strlen(r);
        per(i, 0, len + 1) digit[i] = r[len - i] - '0';
        int ans = dfs(len, 0, 0, 1);
        len = strlen(l);
        per(i, 0, len + 1) digit[i] = l[len - i] - '0';
        digit[1]--;
        for (int i = 1; digit[i] < 0; i++) {
            digit[i] += 10;
            digit[i + 1]--;
        }
        if (digit[len] == 0) len--;
        ans = (ans - dfs(len, 0, 0, 1) + mod) % mod;
        printf("%d\n", ans);
    }
}

你可能感兴趣的:(Codeforces,数位统计dp)