1084. 数字游戏 II
题目链接
1084. 数字游戏 II
由于科协里最近真的很流行数字游戏。
某人又命名了一种取模数,这种数字必须满足各位数字之和 \(mod\ N\) 为 \(0\)。
现在大家又要玩游戏了,指定一个整数闭区间 \([a.b]\),问这个区间内有多少个取模数。
输入格式
输入包含多组测试数据,每组数据占一行。
每组数据包含三个整数 \(a,b,N\)。
输出格式
对于每个测试数据输出一行结果,表示区间内各位数字和 \(mod\ N\) 为 \(0\) 的数的个数。
数据范围
\(1 \le a,b \le 2^{31}-1\),
\(1 \le N < 100\)
输入样例:
1 19 9
输出样例:
2
解题思路
数位dp
-
状态表示:\(f[i][j][k]\) 表示 \(i\) 位数,最后一位为 \(k\),且各位之和对 \(N\) 的余数为 \(j\) 的方案数
-
状态计算:\(f[i][j][k]+=f[i-1][((j-k)\%N+N)\%N][t]\),其中 \(0\leq j,t\leq 9\)
利用 \(f[i][j][k]\) 即可求得前 \(i\) 位数的各位数之和整除 \(N\) 的整数个数 \(s[i]\),即要求 \(1\sim x\) 的满足条件的整数个数,记 \(x\) 的位数为 \(n\),则前 \(n-1\) 位的贡献为 \(s[n-1]\),故现在只用讨论 \(n\) 位整数且不大于 \(x\) 的满足条件的整数个数,类似于 1083. Windy数,每一位每一位考虑,同样对于第一位需要特判,因为第一位不能为 \(0\),同时记录前面的数的和 \(md\),对于小于当前位 \(A[i]\) 的 \(j\),其贡献为 \(f[n-i+1][(N-md%N)%N][j]\),最后,如果该数本身各位之和整除 \(N\) 的话,还要加上该数本身的贡献
- 时间复杂度:\(O(9\times 9\times 10\times N+10\times logw)\)
代码
// Problem: 数字游戏 II
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/description/1086/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
//
// Powered by CP Editor (https://cpeditor.org)
// %%%Skyqwq
#include <bits/stdc++.h>
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
template <typename T> void inline read(T &x) {
int f = 1; x = 0; char s = getchar();
while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
x *= f;
}
int a,b,N;
int f[15][105][15],s[15];
int n,A[15];
void init()
{
memset(f,0,sizeof f);
memset(s,0,sizeof s);
for(int i=0;i<=9;i++)f[1][i%N][i]=1;
for(int i=2;i<=10;i++)
for(int j=0;j<N;j++)
for(int k=0;k<=9;k++)
for(int t=0;t<=9;t++)
f[i][j][k]+=f[i-1][((j-k)%N+N)%N][t];
for(int i=1;i<=10;i++)
for(int j=1;j<=9;j++)s[i]+=f[i][0][j];
for(int i=1;i<=10;i++)s[i]+=s[i-1];
}
int get(int x)
{
if(x==0)return 0;
n=0;
do
{
A[++n]=x%10;
x/=10;
}while(x);
reverse(A+1,A+1+n);
int res=s[n-1];
int md=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<A[i];j++)
{
if(i==1)
{
if(j)res+=f[n][0][j];
}
else
res+=f[n-i+1][(N-md%N)%N][j];
}
md+=A[i];
}
if(md%N==0)res++;
return res;
}
int main()
{
while(~scanf("%d%d%d",&a,&b,&N))
{
init();
printf("%d\n",get(b)-get(a-1));
}
return 0;
}