Investigation
题目描述:对于每个样例给出 l , r , k l,r,k l,r,k ,问在 [ l , r ] [l,r] [l,r] 中,有多少数字可以被 k k k 整除且其数位和也被 k k k 整除。
考虑数位 d p dp dp ,我们首先想像普通的数位 d p dp dp 一样,可以维护一个当前数字 m o d k mod\ k mod k和数位和 m o d k mod\ k mod k 两个状态,但是我们发现这个 k k k 很大,但是我们又可以发现一个问题,给出的 l , r l,r l,r 是在 i n t int int 范围内的,这个范围内的最大数位和也才 82 82 82 ,且不会有数位和为 0 0 0 的情况出现,那么当 k > 82 k > 82 k>82 的时候,任何一个范围内的所有数字的数位和 m o d k mod\ k mod k 都会等于其数位和本身,且不可能为 0 0 0 ,所以当 k > 82 k>82 k>82 的时候,就直接输出 0 0 0 即可,小于等于的话我们就可以用数位 d p dp dp 解决。第一维表示当前放第几位,第二维表示是否有最高位限制,第三维表示当前数字和 m o d k mod\ k mod k ,第四维表示当前数位和 m o d k mod\ k mod k 。
#include <bits/stdc++.h>
using namespace std;
int l, r, k;
int dp[10][2][90][90];
vector<int> num;
int dfs(int pos, int limit, int smod, int dsmod) {
if (pos < 0) return (smod == 0 && dsmod == 0);
if (~dp[pos][limit][smod][dsmod]) return dp[pos][limit][smod][dsmod];
int Max = limit ? num[pos] : 9, ans = 0;
for (int i = 0; i <= Max; ++i) {
ans += dfs(pos - 1, limit && i == num[pos], (10 * smod + i) % k, (dsmod + i) % k);
}
dp[pos][limit][smod][dsmod] = ans;
return ans;
}
int cal(int x) {
memset(dp, -1, sizeof dp);
num.clear();
while(x) {
num.push_back(x % 10);
x /= 10;
}
return dfs((int)num.size() - 1, 1, 0, 0);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int T, cnt = 0;
scanf("%d", &T);
while(T--) {
scanf("%d%d%d", &l, &r, &k);
if (k > 82) {
printf("Case %d: 0\n", ++cnt);
}
else {
printf("Case %d: %d\n", ++cnt, cal(r) - cal(l - 1));
}
}
}