码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 5800 (DP)

时间:2016-08-04 21:25:27      阅读:116      评论:0      收藏:0      [点我收藏+]

标签:

Problem To My Girlfriend (HDU 5800)

题目大意

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

  求 : 

   技术分享

  f (i,j,k,l,m) 指必定选第i,j号元素,必定不选k,l号元素,选的元素总和为m的子集个数。

解题分析

  一开始想了个n^3的DP,f[j][k]表示选j个数总和为k的方案数,然后一直想着怎么去优化,陷进死胡同,到比赛结束还没想出来。

  看了题解后,感觉智商被藐视了。

  题解的做法是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 <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cmath>
 5 using namespace std;
 6 
 7 #define N 1008
 8 #define mo 1000000007
 9 
10 int dp[N][N][3][3];
11 int a[N];
12 
13 void add(int &x,int y){
14     x = x + y;
15     if (x >= mo) x -= mo;
16 }
17 int main(){
18     int T;
19     scanf("%d",&T);
20     while (T--){
21         int n,s;
22         scanf("%d%d",&n,&s);
23         for (int i=1;i<=n;i++) scanf("%d",&a[i]);
24         memset(dp,0,sizeof(dp));
25         dp[0][0][0][0]=1;
26         for (int i=1;i<=n;i++)
27             for (int j=0;j<=s;j++)
28                 for (int s1=0;s1<=2;s1++)
29                     for (int s2=0;s2<=2;s2++){
30                         add(dp[i][j][s1][s2],dp[i-1][j][s1][s2]);
31                         if (j>=a[i]) add(dp[i][j][s1][s2],dp[i-1][j-a[i]][s1][s2]);
32                         if (s1>0 && j>=a[i])
33                             add(dp[i][j][s1][s2],dp[i-1][j-a[i]][s1-1][s2]);
34                         if (s2>0)
35                             add(dp[i][j][s1][s2],dp[i-1][j][s1][s2-1]);
36                     }
37         int ans=0;
38         for (int i=0;i<=s;i++) add(ans,dp[n][i][2][2]);
39         printf("%I64d\n",ans*4ll % mo);
40     }
41 }
View Code

 

HDU 5800 (DP)

标签:

原文地址:http://www.cnblogs.com/rpSebastian/p/5738192.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!