UVA11361 Investigating Div-Sum Property(数位dp)

转载请注明出处: http://www.cnblogs.com/fraud/           ——by fraud

题目意思:问在区间[A,B]有多少个数不仅满足自身是k的倍数,而且其各个位数上的和(十进制)也是k的倍数。

分析:数位dp

首先注意到1+9*9=82,即k最大只能是82,所以,在大于82是直接输出答案为0;

dp[i][j][t]——表示从左往右递推到第i位时(后面所有位数用0填充),各个位数上的和mod k等于j,且这个数mod k等于t时的方案数

状态转移方程为dp[i][j][t]=∑dp[i-1][((j-x)%k+k)%k][((t-x*10^i)%k+k)%k]  (x=0,1,2,……,9)

注意递推的时候相应的位次上是有限制的,并且不要忘记判断其自身

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 int k;
 5 int d[10];
 6 int p[11];
 7 int dp[10][110][110];
 8 int dfs(int size,int n,int m)
 9 {
10     if(!size)
11     {
12         if(n==0&&m==0)return 1;
13         return 0;
14     }
15     if(dp[size][n][m]>=0)return dp[size][n][m];
16     dp[size][n][m]=0;
17     for(int i=0;i<10;i++)
18     {
19         dp[size][n][m]+=dfs(size-1,((n-i)%k+k)%k,((m-i*p[size-1])%k+k)%k);
20     }
21     return dp[size][n][m];
22 }
23 int solve(int num)
24 {
25     int n=0,m=0,size=0,ans=0;
26     if(num==0)return 1;
27     while(num)
28     {
29         d[size++]=num%10;
30         temp+=d[size-1];
31         num/=10;
32     }
33     d[0]++;
34     for(int i=size-1;i>=0;i--)
35     {
36         for(int j=0;j<d[i];j++)
37         {
38             ans+=dfs(i,((k-n-j)%k+k)%k,((k-m-j*p[i])%k+k)%k);
39         }
40         n=(n+d[i])%k;
41         m=(m+d[i]*p[i])%k;
42 
43     }
44     return ans;
45 
46 }
47 
48 int main()
49 {
50     ios::sync_with_stdio(false);
51     p[0]=1;
52     for(int i=1;i<10;i++)p[i]=p[i-1]*10;
53     int a,b,t;
54     cin>>t;
55     while(t--)
56     {
57         cin>>a>>b>>k;
58         if(k>82)cout<<0<<endl;
59         else
60         {
61             memset(dp,-1,sizeof(dp));
62             cout<<solve(b)-solve(a-1)<<endl;
63         }
64     }
65     return 0;
66 }
View Code

 

posted on 2014-11-09 21:11  xyiyy  阅读(229)  评论(0编辑  收藏  举报

导航