AcWing 1084. 数字游戏 II

题目传送门

题目描述

由于科协里最近真的很流行数字游戏。

某人又命名了一种取模数,这种数字必须满足各位数字之和 mod N 为 0。

现在大家又要玩游戏了,指定一个整数闭区间 [a.b],问这个区间内有多少个取模数。

输入格式

输入包含多组测试数据,每组数据占一行。
每组数据包含三个整数 a,b,N。

输出格式

对于每个测试数据输出一行结果,表示区间内各位数字和 mod N 为 0 的数的个数。

数据范围

1≤a,b≤231−1,
1≤N<100

输入样例:

1 19 9

输出样例:

2

解题思路:
树形DP:
跟 数字游戏 I 都是一个思路,只不过处理左分支的做法不同
f(i, j, k)表示当前有 i 位,最高位为 j,且 % m 的余数为 k 的情况

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
const int N = 15;
int f[N][N][110];
int l, r, m;
int mod(int a, int b)  //防止出现负数
{
    return (a % b + b) % b;
}
void init()
{
    memset(f, 0, sizeof f);
    for(int i = 0; i <= 9; i++)f[1][i][i % m]++;
    for(int i = 2; i < N; i++)
        for(int j = 0; j <= 9; j++)
            for(int k = 0; k < m; k++)
                for(int x = 0; x <= 9; x++)
                    f[i][j][k] += f[i - 1][x][mod(k - j, m)];//等于i - 1位,最高位为 x, 所有模数为K - J的情况之和,
}
int dp(int n)
{
    if(n == 0)return 1;
    vector<int> nums;
    while(n)nums.push_back(n % 10), n /= 10;
    int res = 0;   //存答案
    int last = 0;  //存前面各位数字之和
    for(int i = nums.size() - 1; i >= 0; i--){
        int x = nums[i];
        for(int j = 0; j < x; j++)
            res += f[i + 1][j][mod(-last, m)];  //前面各位数的和为last, (last + p) % m == 0 等同于(last - last) % m = 0,即模数为-last
        last += x;
        if(i == 0 && last % m == 0)res++;//判断最后一位的情况
    }
    return res;
}
int main()
{
    while(cin >> l >> r >> m){
        init();
        cout << dp(r) - dp(l - 1) << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43328040/article/details/106843314
今日推荐