标签:
题目:给出K个数,使得这K个数的和为N,LCM为M,问有多少种
f[i][j][k]表示选i个数,总和为j,最小公倍数为k
memery卡的比较紧,注意不要开太大,按照题目数据开
这种类型的dp也是第一次做
1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000000007 10 const double eps=1e-5; 11 #define cl(a) memset(a,0,sizeof(a)) 12 #define ts printf("*****\n"); 13 const int MAXN=1005; 14 int dp[104][MAXN][50],K; 15 int hash[MAXN],num[50],LCM[50][50]; 16 int n,m,tt; 17 int gcd(int a,int b) 18 { 19 if(b==0)return a; 20 return gcd(b,a%b); 21 } 22 int lcm(int a,int b) 23 { 24 return a/gcd(a,b)*b; 25 } 26 int main() 27 { 28 int i,j,k; 29 #ifndef ONLINE_JUDGE 30 freopen("1.in","r",stdin); 31 #endif 32 while(scanf("%d%d%d",&n,&m,&K)!=EOF) 33 { 34 int cnt=0; 35 cl(num),cl(hash); 36 for(i=1;i<=m;i++) 37 { 38 if(m%i==0) 39 { 40 cnt++; 41 num[cnt]=i; 42 hash[i]=cnt; //离散化处理 43 } 44 } 45 cl(dp); 46 for(i=1;i<=cnt;i++) 47 { 48 int x=num[i]; 49 dp[1][x][hash[x]]=1; 50 for(j=1;j<=cnt;j++) 51 { 52 int y=num[j]; 53 LCM[i][j]=lcm(x,y); 54 } 55 } 56 for(i=1;i<K;i++) 57 for(j=i;j<n;j++) //枚举和 58 for(k=1;k<=cnt&&j+num[k]<=n;k++) //前一状态 59 for(int r=1;r<=cnt;r++) //后一状态 60 if(dp[i][j][r]>0) 61 { 62 int x,t; 63 x=num[k]; 64 t=hash[LCM[r][k]]; 65 dp[i+1][j+x][t]=(dp[i+1][j+x][t]+dp[i][j][r])%MOD; 66 } 67 printf("%d\n",dp[K][n][hash[m]]); 68 } 69 }
zoj 3662 第37届ACM/ICPC长春赛区H题(DP)
标签:
原文地址:http://www.cnblogs.com/cnblogs321114287/p/4430636.html