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;
}
posted @ 2022-12-07 21:55  zyy2001  阅读(57)  评论(0编辑  收藏  举报