HDU 4427 Math Magic(动态规划)

【题意】

给定N,M,K:N、M<=1000,K<=100

求满足正数:

1. SUM (A1, A2, ..., Ai, Ai+1,..., AK) = N
2. LCM (A1, A2, ..., Ai, Ai+1,..., AK) = M

条件(A1, A2, ..., Ai, Ai+1,..., AK) 的方案数。

注意:(1,2)和(2,1)是两种方案。

 

【分析】

状态dp[k][i][j]表示考虑第k个数时,前面k个数的sum位i,lcm为j的方案数。

决策为枚举当前数。

最后答案为dp[K][N][M]

总复杂度为O(K*N*M*M),显然不行。

【优化】

考虑到每个数只能是M的因子,那么dp[k][i][j]表示sum为i,lcm为m的第j大的因子。枚举决策为m的因子。

总复杂度为O(K*N*30*30),最多有30个因子。

还可以使用滚动数组优化空间。

 

 1 #include<stdio.h>
 2 #include<math.h>
 3 #include<string.h>
 4 #define LL long long
 5 #define MOD 1000000007
 6 
 7 int gcd(int a,int b)
 8 {
 9     return b==0?a:gcd(b,a%b);
10 }
11 int lcm[1010][1010];
12 int N,M,K;
13 int seq[33];
14 int tot;
15 int hash[1010];
16 void init()
17 {
18 
19     tot = 0;
20     for (int i=1;i<=M;i++)
21         if (M % i == 0)
22         {
23             seq[++tot] = i;
24             hash[i] = tot;
25         }
26     return ;
27 }
28 
29 
30 
31 LL dp[2][1010][33];
32 
33 int main()
34 {
35     for (int i=1;i<=1000;i++){
36         for (int j=1;j<=1000;j++)
37             lcm[i][j] = i*j/gcd(i,j);
38         lcm[0][i] = i;
39     }
40     while (scanf("%d%d%d",&N,&M,&K)==3)
41     {
42         init();
43       //  printf("%d\n",lcm[9][18]);
44         memset(dp,0,sizeof(dp));
45         dp[0][0][1] = 1;
46         int t = 0,s;
47         for (int k=1;k<=K;k++)
48         {
49             s = t;
50             t = 1 - t;
51             for (int i=0;i<=N;i++)
52                 for (int j=0;j<=tot;j++)
53                     dp[t][i][j] = 0;
54             for (int i=0;i<=N;i++)
55                 for (int j=1;j<=tot;j++)
56                     if (dp[s][i][j] > 0)
57                     {
58                         //printf("%d %d\n",i,seq[j]);
59                         for (int jj=1;jj<=tot;jj++){
60                             int sum = i + seq[jj];
61                             int lll = lcm[seq[j]][seq[jj]];
62                             if (sum<=N && lll<=M)
63                             {
64                            // printf("%d %d %d %d\n",sum,seq[j],seq[jj],lll);
65                                 int ppp = hash[lll];
66                                 dp[t][sum][ppp] = (dp[t][sum][ppp] + dp[s][i][j]) % MOD;
67                             }
68                         }
69 
70                     }
71             //printf("********************\n");
72         }
73         LL ans = (dp[t][N][tot] % MOD + MOD) % MOD;
74 
75         printf("%I64d\n",ans);
76     }
77     return 0;
78 }
hdu4427

 

 

 

 

 

 

转载于:https://www.cnblogs.com/wangsouc/articles/3302574.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值