题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1068
题意:给出区间[A,B]一个数K。求区间中能被K整数且各位数字之和也能被K整除的数的个数。
思路:总的思路是,由于数字都小于2^31,所以最多10位,也就是各位数字之和最多为90,也就是K大于90时答案必定为0。因此只需要考虑K小于等于90的情况。我是这样考虑的f[i][j][k]表示前i位数个位数字之和为j模K的余数为k的数量。DP即可。
下面的第一份代码是我的思路。第二份是网上看别人的。。。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 using namespace std; 5 6 int C,num=0; 7 int f[15][100][100],a[15]; 8 int A,B,K; 9 10 int getCount(int x) 11 { 12 int t=0,i,k; 13 while(x) 14 { 15 a[++t]=x%10; 16 x/=10; 17 } 18 for(i=1;i<=t/2;i++) 19 { 20 k=a[i]; 21 a[i]=a[t+1-i]; 22 a[t+1-i]=k; 23 } 24 return t; 25 } 26 27 int DP1(int t,int x) 28 { 29 if(t==0) return 0; 30 int i,j,k,p; 31 memset(f,0,sizeof(f)); 32 for(i=1;i<=9;i++) f[1][i][i%x]++; 33 for(i=2;i<=t;i++) for(j=1;j<=(i-1)*9;j++) for(k=0;k<x;k++) if(f[i-1][j][k]) 34 { 35 for(p=0;p<=9;p++) f[i][j+p][(k*10+p)%x]+=f[i-1][j][k]; 36 } 37 int ans=0; 38 for(i=1;i<=t;i++) for(j=x;j<=90;j+=x) ans+=f[i][j][0]; 39 return ans; 40 } 41 42 int DP(int t,int x,int low[],int high[]) 43 { 44 if(t==0) return 0; 45 int i,j,k,p; 46 memset(f,0,sizeof(f)); 47 for(i=low[1];i<=high[1];i++) f[1][i][i%x]++; 48 for(i=2;i<=t;i++) for(j=1;j<=(i-1)*9;j++) for(k=0;k<x;k++) if(f[i-1][j][k]) 49 { 50 for(p=low[i];p<=high[i];p++) 51 f[i][j+p][(k*10+p)%x]+=f[i-1][j][k]; 52 } 53 int ans=0; 54 for(j=x;j<=90;j+=x) ans+=f[t][j][0]; 55 return ans; 56 } 57 58 int OK(int x) 59 { 60 if(x%K) return 0; 61 int t=0; 62 while(x) t+=x%10,x/=10; 63 return t%K==0; 64 } 65 66 int cal(int x) 67 { 68 if(x==0) return 0; 69 int t=getCount(x),low[15],high[15],i; 70 for(i=1;i<=10;i++) 71 { 72 low[i]=0; 73 high[i]=9; 74 } 75 low[1]=1; 76 int ans=DP1(t-1,K); 77 for(i=1;i<=t;i++) 78 { 79 low[i-1]=++high[i-1]; 80 high[i]=a[i]-1; 81 ans+=DP(t,K,low,high); 82 } 83 return ans+OK(x); 84 } 85 86 int main() 87 { 88 for(scanf("%d",&C);C--;) 89 { 90 scanf("%d%d%d",&A,&B,&K); 91 int ans; 92 if(K>90) ans=0; 93 else ans=cal(B)-cal(A-1); 94 printf("Case %d: %d\n",++num,ans); 95 } 96 return 0; 97 } 98 99 #include <iostream> 100 #include <cstdio> 101 #include <cstring> 102 using namespace std; 103 104 int C,num=0; 105 int f[15][100][100][2]; 106 int A,B,K,len; 107 char s[20]; 108 109 int DFS(int dep,int mod1,int mod2,int flag) 110 { 111 if(dep==len) return !mod1&&!mod2; 112 int &ans=f[dep][mod1][mod2][flag]; 113 if(ans!=-1) return ans; 114 ans=0; 115 int i,t=s[dep]-'0'; 116 for(i=0;i<10;i++) 117 { 118 if(flag&&i>t) break; 119 ans+=DFS(dep+1,(mod1*10+i)%K,(mod2+i)%K,i<t?0:flag); 120 } 121 return ans; 122 } 123 124 int cal(int x) 125 { 126 if(K==1) return x; 127 sprintf(s,"%d",x); 128 len=strlen(s); 129 memset(f,-1,sizeof(f)); 130 return DFS(0,0,0,1); 131 } 132 133 int main() 134 { 135 for(scanf("%d",&C);C--;) 136 { 137 scanf("%d%d%d",&A,&B,&K); 138 int ans; 139 if(K>90) ans=0; 140 else ans=cal(B)-cal(A-1); 141 printf("Case %d: %d\n",++num,ans); 142 } 143 return 0; 144 }