hdu4427Math Magic

4427

dp[i][j][k] i为K位的最小公倍数 j为k位的和 k以滚动数组的形式

这题最棒的是 有一个强有力的剪枝 组成公倍数m的肯定都是M的质因子 这样1000里面最多就30多个 复杂度可过了

 1 #include <iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<stdlib.h>
 6 #include<queue>
 7 using namespace std;
 8 #define mod 1000000007
 9 int dp[1010][1010][2];
10 int q[110][1010],f[1010],lc[1010][1010];
11 int p[1010];
12 int gcd(int a,int b)
13 {
14     return b==0?a:gcd(b,a%b);
15 }
16 int main()
17 {
18     int n,m,k,i,j,g;
19     for(i = 1 ; i <= 1000 ; i++)
20         for(j = 1; j <= 1000 ; j++)
21         lc[i][j] = i*j/gcd(i,j);
22     while(scanf("%d%d%d",&n,&m,&k)!=EOF)
23     {
24         int o;
25         int to = 0;
26         for(i =1; i <= m ; i++)
27         if(m%i==0)
28         {
29             to++;
30             p[to] = i;
31         }
32         memset(dp,0,sizeof(dp));
33         for(i = 1 ; i <= min(n,m) ; i++)
34         {
35             dp[i][i][1] = 1;
36         }
37         for(i = 2; i <= k; i++)
38         {
39             for(o = 1; o <= to ; o++)
40                 for(g = 1; g <= n ; g++)
41                 dp[p[o]][g][i%2] = 0;
42                 for(j = 1 ; j <= to ; j++)
43                 {
44                     for(g = i-1; g <= n ; g++)
45                     {
46                         if(dp[p[j]][g][(i-1)%2]==0)
47                         continue;
48                         for(o = 1 ; o <= to ; o++)
49                         {
50                             int x = lc[p[j]][p[o]];
51                             if(g+p[o]>n)
52                             break;
53                             if(x>m)
54                             continue;
55                             dp[x][g+p[o]][i%2] = (dp[x][g+p[o]][i%2]+dp[p[j]][g][(i-1)%2])%mod;
56                         }
57                     }
58                 }
59         }
60         printf("%d\n",dp[m][n][k%2]);
61     }
62     return 0;
63 }
View Code

 

posted @ 2013-10-31 10:11  _雨  阅读(238)  评论(0编辑  收藏  举报