zoj 3662 第37届ACM/ICPC长春赛区H题(DP)

题目:给出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 }

 

你可能感兴趣的:(ICPC)