http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3682
题目意思:
有两种球迷,分别有s1、s2人,然后有n个广场,每个广场ki个人。每个广场要么只有一种球迷,要么两种球迷数量相等。问安排数量
注意题目有一个比较重要的条件 Sum(ki) == s1 + s2,漏看这个条件的话,此题难度就#¥@¥%#%……@……¥
有了这个条件,我们可以知道每个广场都是满的。我们考虑人比较少的那个球迷,取s = min(s1, s2)
每个广场要么全部分给该类球迷,要么不分给该类球迷,如果该广场能容纳的人数为偶数,则亦可以选择一半为该球迷。
可以发现,方案数是等价的,一类球迷确定了,另一类也就确定了。
熟悉的背包问题。
代码如下:
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 using namespace std; 6 int s,n,a[210]; 7 int dp[100100]; 8 const int md=1000000007; 9 int main() 10 { 11 int s1,s2; 12 while (~scanf("%d%d",&s1,&s2)) 13 { 14 s=min(s1,s2); 15 scanf("%d",&n); 16 for(int i=0;i<n;i++)scanf("%d",a+i); 17 int sum=0; 18 memset(dp,0,sizeof dp); 19 dp[0]=1; 20 for(int i=0;i<n;i++){ 21 sum+=a[i]; 22 if(sum>s)sum=s; 23 if(a[i]&1) 24 { 25 for(int j=sum;j>=a[i];j--){ 26 dp[j]+=dp[j-a[i]]; 27 if(dp[j]>=md) dp[j]-=md; 28 } 29 } 30 else{ 31 int ed=a[i]/2; 32 for(int j=sum;j>=ed;j--){ 33 if(j>=a[i]){ 34 dp[j]+=dp[j-a[i]]; 35 if(dp[j]>=md) dp[j]-=md; 36 } 37 dp[j]+=dp[j-ed]; 38 if(dp[j]>=md) dp[j]-=md; 39 } 40 } 41 } 42 printf("%d\n",dp[s]); 43 } 44 return 0; 45 }