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)
注意递推的时候相应的位次上是有限制的,并且不要忘记判断其自身
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }