LOJ-1068 Investigation(数位dp)

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));
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值