您的位置:首页 > 其它

LightOJ - 1068 Investigation(数位DP)

2015-10-28 23:07 281 查看
题目大意:给你三个数,l, r, k,问[l,r] 这个范围内,有多少个数满足该数能被k整除,且所有数位和能被k整除

解题思路:一个大剪枝,因为给的数字是小于2^31,10位数,且最高位为2,所以最大的数位和就不会超过90了,所以k超过90的,答案都是0

接下来就是数位DP了,用dp[pos][sum][mod]表示当前在i位,前面所有数位的和和k的余数是sum,前面的数和k的余数是mod

#include <cstdio>
#include <cstring>
using namespace std;
const int N = 10;
int dp
[N * 10][N * 10];
int bit
;
int l, r, k, cas = 1;

int dfs(int pos, int sum, int mod, int limit) {
if (pos == -1) return sum == 0 && mod == 0;
if (!limit && ~dp[pos][sum][mod]) return dp[pos][sum][mod];

int n = limit ? bit[pos] : 9;
int ans = 0;
for (int i = 0; i <= n; i++) {
int s = (sum + i) % k;
int t = (mod * 10 + i) % k;
ans += dfs(pos - 1, s, t, limit && i == n);
}
if (!limit) dp[pos][sum][mod] = ans;
return ans;
}

int DP(int x) {
if (!x) return 1;
int cnt = 0;
while (x) {
bit[cnt++] = x % 10;
x /= 10;
}
memset(dp, -1, sizeof(dp));
return dfs(cnt - 1, 0, 0, 1);
}

void solve() {
scanf("%d%d%d", &l, &r, &k);
if (k >= 90) {
printf("Case %d: %d\n", cas++, 0);
return ;
}
printf("Case %d: %d\n", cas++, DP(r) - DP(l - 1));
}

int main() {
int test;
scanf("%d", &test);
while (test--) solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: