洛谷 P4127[AHOI2009]同类分布
这道题的状态其实很好想,dp[x][st][sum]表示前x位原数是st和是sum的个数。
问题是原数太大了,状态开不下。
因为这道题我们实际上要的是st%sum,而sum最大只有172,所以不妨对st取个模,如果st%mod==0,sum%mod==0,那么st%mod==0.
因为这里模数最多只到sum最大值,所以直接枚举模数对每一个模数做一遍数位DP然后求和。
这里注意,以前因为状态相同,所以DP的值可以重复利用,但是这里的值里面隐含了取模的条件,所以每次DP都要重新初始化。
下附代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 ll dp[19][173][173],dim[20]; 5 ll dfs(int x,int st,int sum,int jb,int mod){ 6 if (!x){ 7 if (sum==mod && st==0) return 1; 8 else return 0; 9 } 10 if (!jb && dp[x][sum][st]!=-1) return dp[x][sum][st]; 11 ll ret=0; 12 int maxn=9; 13 if (jb) maxn=dim[x]; 14 for (int i=0; i<=maxn; i++){ 15 ret+=dfs(x-1,(st*10+i)%mod,sum+i,(jb==1 && i==maxn),mod); 16 } 17 if (!jb) return dp[x][sum][st]=ret; 18 return ret; 19 } 20 int main(){ 21 ll a,b; 22 scanf("%lld%lld",&a,&b); 23 a--; 24 int len=0; 25 while (a){ 26 dim[++len]=a%10; 27 a/=10; 28 } 29 ll resl=0; 30 for (int i=1; i<=9*len; i++){ 31 memset(dp,-1,sizeof(dp)); 32 resl+=dfs(len,0,0,1,i); 33 } 34 len=0; 35 while (b){ 36 dim[++len]=b%10; 37 b/=10; 38 } 39 ll resr=0; 40 for (int i=1; i<=9*len; i++){ 41 memset(dp,-1,sizeof(dp)); 42 resr+=dfs(len,0,0,1,i); 43 } 44 printf("%lld",resr-resl); 45 }