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

 

你可能感兴趣的:(Math)