zoj 3662 Math Magic(DP)
挺水的dp,脑抽把mod多打了个0结果弹了2次。
好吧,我们记录dp[i][j][k]为选i个数字,和为j,lcm为k的个数有多少种
接下来枚举第i+1个数字进行转移就行了,开三维会MLE,可以用滚动数组做。
我的做法有点类似背包,将lcm和sum从大到小枚举,这样避免重复。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #define mod 1000000007 5 using namespace std; 6 int dp[1010][40]; 7 int f[1010][1010]; 8 int n,m,k; 9 int a[1010],aa[1010]; 10 int gcd(int a,int b){ 11 if(f[a][b]!=-1) return f[a][b]; 12 if(b) return f[a][b]=gcd(b,a%b); 13 else return f[a][b]=a; 14 } 15 int lcm(int a,int b){ 16 return a/gcd(a,b)*b; 17 } 18 19 int main(){ 20 memset(f,-1,sizeof f); 21 while(~scanf("%d%d%d",&n,&m,&k)){ 22 memset(dp,0,sizeof dp); 23 int ct=0; 24 for(int i=1;i<=m;i++){ 25 if(m%i==0) a[ct++]=i; 26 } 27 for(int i=0;i<ct;i++) aa[a[i]]=i; 28 int cur=0; 29 for(int i=0;i<ct;i++) dp[a[i]][i]=1; 30 for(int i=2;i<=k;i++,cur=1-cur){ 31 for(int j=ct-1;j>=0;j--){//i-1 lcm 32 for(int p=n;p>=0;p--){//i-1 sum 33 if(!dp[p][j]) continue; 34 for(int q=0;q<ct&&a[q]+p<=n;q++){ 35 int x=lcm(a[j],a[q]); 36 //cout<<p<<" "<<a[j]<<" "<<a[q]<<endl; 37 dp[p+a[q]][aa[x]]=(dp[p+a[q]][aa[x]]+dp[p][j])%mod; 38 } 39 dp[p][j]=0; 40 } 41 } 42 } 43 printf("%d\n",dp[n][ct-1]); 44 } 45 return 0; 46 }