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
",dp[n][ct-1]);
44     }
45     return 0;
46 }
zoj3662
原文地址:https://www.cnblogs.com/wonderzy/p/3412604.html