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.

125 lines
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 $](https://www.acwing.com/problem/content/1086/)
### 一、题目描述
由于科协里最近真的很流行数字游戏。
某人又命名了一种取模数,这种数字必须满足各位数字之和 $mod$ $N$ 为 $0$。
现在大家又要玩游戏了,指定一个整数闭区间 $[a.b]$,问这个区间内有多少个取模数。
**输入格式**
输入包含多组测试数据,每组数据占一行。
每组数据包含三个整数 $a,b,N$。
**输出格式**
对于每个测试数据输出一行结果,表示区间内各位数字和 $mod$ $N$ 为 $0$ 的数的个数。
**数据范围**
$1≤a,b≤2^{31}1,1≤N<100$
**输入样例**
```cpp {.line-numbers}
1 19 9
```
**输出样例**
```cpp {.line-numbers}
2
```
### 二、解题思路
* 以$u$,$st \% mod$为两维数组进行缓存
* 以$u$,$st \% mod$,$mod$为三维数组进行缓存
因为取模的值是每次全新录入的,同时,模值并不大,小于等于$100$,这是我们可以采用以$mod$为第三维缓存结果创造了条件。如果模值是$1e5$的话,个人理解就不能这么干了,就老实的用方法$1$,每次老老实实的`memset(f,-1,sizeof ~f)`吧。
### 三、二维数组状态描述法
```cpp {.line-numbers}
#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;
}
```
### 四、三维数组状态描述法
```cpp {.line-numbers}
#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;
}
```