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

 

你可能感兴趣的:(property)