You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3.6 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

AcWing 1084. 数字游戏 II

一、题目描述

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

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

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

输入格式 输入包含多组测试数据,每组数据占一行。

每组数据包含三个整数 a,b,N

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

数据范围 1≤a,b≤2^{31}1,1≤N<100

输入样例

1 19 9

输出样例

2

二、解题思路

  • u,st \% mod为两维数组进行缓存
  • u,st \% mod,mod为三维数组进行缓存

因为取模的值是每次全新录入的,同时,模值并不大,小于等于100,这是我们可以采用以mod为第三维缓存结果创造了条件。如果模值是1e5的话,个人理解就不能这么干了,就老实的用方法1,每次老老实实的memset(f,-1,sizeof ~f)吧。

三、二维数组状态描述法

#include <bits/stdc++.h>

using namespace std;

const int N = 32;
const int M = 100; // n<=100,所有 mod n 的结果最大是99

int mod;
int a[N], al;
int f[N][M];

int dfs(int u, int st, bool op) {
    if (u == 0) return st % mod == 0; // 各位数字和 %n == 0就是一个答案

    if (!op && ~f[u][st]) return f[u][st];

    int ans = 0, up = op ? a[u] : 9;
    for (int i = 0; i <= up; i++)
        ans += dfs(u - 1, (st + i) % mod, op && i == a[u]);

    if (!op) f[u][st] = ans;
    return ans;
}

int calc(int x) {
    // 疑问为什么本题不能将memset放在整体上呢是因为取模造成的吗
    // 答是的因为n是每次全新输入的,如果有兴趣可以再加一维维护n
    memset(f, -1, sizeof f);
    al = 0;
    while (x) a[++al] = x % 10, x /= 10;
    // 某人又命名了一种取模数,这种数字必须满足各位数字之和 mod N 为 0。
    // 前0位数字和为0,st = 0
    return dfs(al, 0, true);
}

int main() {
    int l, r;
    while (cin >> l >> r >> mod)
        printf("%d\n", calc(r) - calc(l - 1));
    return 0;
}

四、三维数组状态描述法

#include <bits/stdc++.h>
using namespace std;

const int N = 32;
const int M = 100; // n<=100,所有 mod n 的结果最大是99

int mod;
int a[N], al;
int f[N][M][M];

int dfs(int u, int st, bool op) {
    if (u == 0) return st % mod == 0; // 各位数字和 %n == 0就是一个答案

    if (!op && ~f[u][st][mod]) return f[u][st][mod];

    int ans = 0, up = op ? a[u] : 9;
    for (int i = 0; i <= up; i++)
        ans += dfs(u - 1, (st + i) % mod, op && i == a[u]);

    if (!op) f[u][st][mod] = ans;
    return ans;
}

int calc(int x) {
    al = 0;
    while (x) a[++al] = x % 10, x /= 10;
    // 某人又命名了一种取模数,这种数字必须满足各位数字之和 mod N 为 0。
    // 前0位数字和为0,st = 0
    return dfs(al, 0, true);
}

int main() {
    // 疑问为什么本题不能将memset放在整体上呢是因为取模造成的吗
    // 答是的因为n是每次全新输入的,如果有兴趣可以再加一维维护n
    memset(f, -1, sizeof f);

    int l, r;
    while (cin >> l >> r >> mod)
        printf("%d\n", calc(r) - calc(l - 1));
    return 0;
}