Lightoj 1068(数位DP)
求一段区间中被k整除,各个位数相加之和被k整除的数的个数。
这不是重点,重点是k太大了,最大值有10000,所以不能直接开那么大的数组。
仔细分析一下可以发现,由于数最大是2的31次方(2147483648),所以当k>90时,直接输出0即可。
#include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; #define LL long long #define maxn 30 LL dp[maxn][100][100]; LL digit[maxn]; LL n,m,K; LL dfs(int len,LL pre,LL before,bool fp) { if(!len) { return pre==0&&before==0; } if(!fp && dp[len][pre][before] != -1) return dp[len][pre][before]; LL ret = 0 ; LL fpmax = fp ? digit[len] : 9; for(int i=0;i<=fpmax;i++) { ret += dfs(len-1,(pre*10+i)%K,(before+i)%K,fp && i == fpmax); } if(!fp) dp[len][pre][before] = ret; return ret; } LL f(LL n) { int len = 0; while(n) { digit[++len] = n % 10; n /= 10; } return dfs(len,0,0,true); } void init() { memset(dp,-1,sizeof(dp)); } int main() { //freopen("test.txt","r",stdin); // cout<< ((LL)1<<31)<<endl; int t; scanf("%d",&t); int Case=0; while(t--) { scanf("%d%d%d",&n,&m,&K); if(K>90) { printf("Case %d: 0\n",++Case); continue; } init(); printf("Case %d: %lld\n",++Case,f(m)-f(n-1)); } return 0; }