洛谷 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都要重新初始化。

下附代码:

 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 }
View Code
原文地址:https://www.cnblogs.com/i-caigou-TT/p/14368968.html