Horse Races
分类:
dp
math
1.题意概述
- 规定
4
和7
是幸运数,而且约定一个数是“辛运数字”当且仅当,相邻两个幸运数字的数位距离不超过 k(1≤k≤1000) ,现在给定你一个区间 [l,r](1≤l≤r≤101000) ,问你这个区间的幸运数字有多少个,答案取模 109+7 。
2.解题思路
- 很显然,这是一道数位dp的题目,两个难点,一个在于大数如何转化,第二个在于如何统计不超过k的距离,第一个我们可以通过读入字符串,然后将字符串倒序就可以实现,但是因为我们是统计的前缀,因此在 l−1 时候模拟大数减法不要忘了可能会出现退位现象。而第二个难点,我们可以直接考虑在dfs时候增加一个限制条件看距离上一个距离是否小于 k <script type="math/tex" id="MathJax-Element-5">k</script>即可,细节很多,参见代码:
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);
}
}