hdu 4427 Math Magic DP

思路:

dp[i][j][k]表示满足前i个数,和为j,lcm为k的数目。

设a为解的第i+1个数。
那么状态转移就为
dp[i+1][j+a][lcm(a,k)]+=dp[i][j][k]。

但是由于三维开不了,所以用滚动数组。

代码如下:

 

 1 #include<iostream>
 2 #include<stdio.h>
 3 #include<algorithm>
 4 #include<iomanip>
 5 #include<cmath>
 6 #include<cstring>
 7 #include<vector>
 8 #define ll __int64
 9 #define pi acos(-1.0)
10 #define MAX 1001
11 #define M 1000000007
12 using namespace std;
13 int num[MAX],LCM[MAX][MAX],dp[2][MAX][MAX],cnt;
14 int gcd(int a,int b)
15 {
16     while(b){
17         int t=a;
18         a=b;
19         b=t%b;
20     }
21     return a;
22 }
23 int lcm(int a,int b)
24 {
25     return a/gcd(a,b)*b;
26 }
27 void init()//预处理出lcm
28 {
29     int i,j;
30     for(i=1;i<MAX;i++){
31         LCM[i][i]=i;
32         for(j=1;j<i;j++)
33             LCM[j][i]=LCM[i][j]=lcm(i,j);
34     }
35 }
36 int main(){
37     int t,n,m,k,i,j,now,v;
38     init();
39     while(scanf("%d%d%d",&n,&m,&k)!=EOF){
40         cnt=0;
41         for(i=1;i<=m;i++)
42             if(m%i==0)
43                 num[cnt++]=i;
44         now=0;
45         for(i=0;i<=n;i++)//不要用memset
46             for(j=0;j<cnt;j++)
47             dp[now][i][num[j]]=0;
48         dp[now][0][1]=1;
49         for(t=1;t<=k;t++){
50             now^=1;
51             for(i=0;i<=n;i++)//不要用memset
52             for(j=0;j<cnt;j++)
53             dp[now][i][num[j]]=0;
54             for(i=t-1;i<=n;i++){
55                 for(j=0;j<cnt;j++){
56                     if(dp[now^1][i][num[j]]==0) continue;
57                     for(v=0;v<cnt;v++){
58                         int s=i+num[v];
59                         int l=LCM[num[j]][num[v]];
60                         if(s>n||m%l!=0) continue;
61                         dp[now][s][l]+=dp[now^1][i][num[j]];
62                         dp[now][s][l]%=M;
63                     }
64                 }
65             }
66         }
67         printf("%d\n",dp[now][n][m]);
68     }
69     return 0;
70 }
View Code

 

 

 

posted @ 2013-08-26 16:54  _随心所欲_  阅读(293)  评论(0编辑  收藏  举报