hud5800_dp

http://acm.hdu.edu.cn/showproblem.php?pid=5800

题意:

给定一个由n个元素组成的序列,和s (n<=1000,s<=1000)

  求 :

题解的做法是f[i][j][s1][s2]表示前i个数总和为j必选s1个必不选s2个的方案数,这样是O(n*s*4)的。

  对于每一个数,有4种选法:选,不选,必选,必不选,然后转移就好了。

  答案就是sigma(f[n][i][2][2]) ,i∈[0,s]。

 1 #include <algorithm>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <cstdio>
 6 #include <vector>
 7 #include <ctime>
 8 #include <queue>
 9 #include <list>
10 #include <set>
11 #include <map>
12 using namespace std;
13 #define mod 1000000007
14 typedef long long LL;
15
16 int dp[1010][1010][4][4];
17 int a[1010];
18 void Add(int &x, int y)
19 {
20     x = (x + y) % mod;
21 }
22 int main()
23 {
24     int n, s, t;
25     scanf("%d", &t);
26     while(t--)
27     {
28         scanf("%d %d", &n, &s);
29         for(int i = 1; i <= n; i++)
30             scanf("%d", a + i);
31         memset(dp, 0, sizeof(dp));
32         dp[0][0][0][0] = 1;
33         for(int i = 1; i <= n; i++)
34         {
35             for(int j = 0; j <= s; j++)
36             {
37                 for(int k = 0; k <= 2; k++)
38                 {
39                     for(int l = 0; l <= 2; l++)
40                     {
41                         Add(dp[i][j][k][l], dp[i - 1][j][k][l]);
42                         if(j >= a[i])
43                             Add(dp[i][j][k][l], dp[i - 1][j - a[i]][k][l]);
44                         if(k > 0 && j >= a[i])
45                             Add(dp[i][j][k][l], dp[i - 1][j - a[i]][k - 1][l]);
46                         if(l > 0)
47                             Add(dp[i][j][k][l], dp[i - 1][j][k][l - 1]);
48                     }
49                 }
50             }
51         }
52         LL res = 0;
53         for(int i = 0; i <= s; i++)
54             res += dp[n][i][2][2];
55         printf("%lld\n", res * 4 % mod);
56     }
57     return 0;
58 }

时间: 2024-09-29 10:09:56

hud5800_dp的相关文章