LightOJ 1068 Investigation (数位dp)

http://www.lightoj.com/volume_showproblem.php?problem=1068


求出区间[A,B]内能被K整除且各位数字之和也能被K整除的数的个数。(1 ≤ A ≤ B < 231 and 0 < K < 10000

算是最简单的数位dp了,k在这里是10000,三维数组都开不开。但是想想会发现A,B最多有10位,各位数字之和不会超过90,那么当 k >= 90时,就不用dp,因为个位数字之和对k取余不会等于0。所以数组只需开到dp[12][90][90]。


#include <stdio.h>
#include <iostream>
#include <map>
#include <set>
#include <list>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL __int64
#define eps 1e-12
#define PI acos(-1.0)
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 4010;

int dp[15][92][92];
int a,b,k;
int dig[15];

int dfs(int len, int mod1, int mod2, int up)
{
	if(len == 0)
		return mod1 == 0 && mod2 == 0;
	if(!up && dp[len][mod1][mod2] != -1)
		return dp[len][mod1][mod2];
	int res = 0;
	int n = up ? dig[len] : 9;
	for(int i = 0; i <= n; i++)
	{
		int tmod1 = (mod1*10 + i)%k;
		int tmod2 = (mod2 + i)%k;
		res += dfs(len-1,tmod1,tmod2,up&&i==n);
	}
	if(!up)
		dp[len][mod1][mod2] = res;
	return res;
}

int cal(int num)
{
	int len = 0;
	while(num)
	{
		dig[++len] = num%10;
		num /= 10;
	}
	return dfs(len,0,0,1);
}

int main()
{
	int test;
	scanf("%d",&test);
	for(int item = 1; item <= test; item++)
	{
		scanf("%d %d %d",&a,&b,&k);
		if(k >= 90)
		{
			printf("Case %d: 0\n",item);
			continue;
		}
		memset(dp,-1,sizeof(dp));
		printf("Case %d: %d\n",item,cal(b) - cal(a-1));
	}
	return 0;
}




你可能感兴趣的:(dp)