#10166. 「一本通 5.3 练习 1」数字游戏【数位 DP】

题目描述

由于科协里最近真的很流行数字游戏,某人又命名了一种取模数,这种数字必须满足各位数字之和 mod N为 0。现在大家又要玩游戏了,指定一个整数闭区间 [a,b],问这个区间内有多少个取模数。

输入格式

题目有多组测试数据。每组只含三个数字 a, b, N。

输出格式

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

样例

Input

1 19 9

Output

2

数据范围与提示
对于全部数据,1≤ a,b≤231-1,1≤N<100。

代码1

#include "stdio.h"
#include "algorithm"
#include "string.h"
using namespace std;
int p;
int dp[20][109];
int s[99];
int dfs(int l,int m,bool limit)
{
	if(!l)
	{
		if(m==0)
			return 1;
		return 0;
	}
	if(!limit&&dp[l][m]!=-1)
		return dp[l][m];
	int shu=0,ans=0;
	if(limit)//这儿看是否受限制,不受限制的话0~9随便取,否则0~s[l],如就算234:此时如果百位是2,那么十位受限制只能取0~3(就是取得数要小于等于234),但如果百位是1,那么十位不受限制,可以取0~9
		shu=s[l];
	else
		shu=9;
	for(int i=0; i<=shu; i++)
		ans+=dfs(l-1,(m+i)%p,limit&&i==s[l]) ;
	if(!limit)
		dp[l][m]=ans;
	return ans;
}
int qqq(int n)
{
	int l=0;
	while(n)
	{
		s[++l]=n%10;
		n/=10;
	}
	return dfs(l,0,1);//分别对应:位数,模,取得值是否受限制
}
int main()
{
	int a,b;
	while(~scanf("%d%d%d",&a,&b,&p))
	{
		memset(dp,-1,sizeof(dp));//每次p值不一定一样
		printf("%d\n",qqq(b)-qqq(a-1));
	}
}

代码2

#include "stdio.h"
#include "algorithm"
#include "string.h"
using namespace std;
int p,s[14];
int dp[14][12][109];//
int mmod(int m)
{
	return (m%p+p)%p;//防止dp数组的第三个括号里的值为负数
}
void init()
{
	for(int i=0; i<=9; i++)
		dp[1][i][i%p]++;//1:此时我们计算的数字为1位数,即长度为1,i是这位数的最高位为多少(如23,最高位为十位,即2),i%p相对于dp[1][i][i%p]来说,最高位为i的长度为1(个位数)对p取余为i%p
//如dp[2][4][9]的值是长度为2(2位数)最高位为4 对p取余为9的总数
	for(int i=2; i<=11; i++)
		for(int j=0; j<=9; j++)
			for(int k=0; k<p; k++)
				for(int jj=0; jj<=9; jj++)
					dp[i][j][k]+=dp[i-1][jj][mmod(k-j)];
}
int qqq(int n)
{
	if(n==0)
		return 1;
	int l=0;
	while(n)
	{
		s[++l]=n%10;
		n/=10;
	}
	int sum=0;
	int d=0;
	for(; l>0; l--)
	{	
		int x=s[l];
		for(int i=0; i<x; i++)
		{
			sum+=dp[l][i][mmod(0-d)];
		}
		d+=x;
		if(l==1&&d%p==0)
			sum++;
	}
	return sum;
}
int main()
{
	int a,b;
	while(~scanf("%d%d%d",&a,&b,&p))
	{
		memset(dp,0,sizeof(dp));
		init();
		printf("%d\n",qqq(b)-qqq(a-1));
	}
}

你可能感兴趣的:(动态规划,动态规划,算法)