LightOJ 1068 Investigation (数位dp)

来源:互联网 发布:安卓windows桌面主题 编辑:程序博客网 时间:2024/06/10 19:48

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;}




0 0
原创粉丝点击