题意:集合划分,使得满足这两个式子,有多少种方案,其中s’为任意子集,s-s’表示补集,t为s中任意元素的组合,其实只要最小的元素满足了,这个式子一定满足
思路:从大到小排序,进行普通01背包求方案数,当前的a[i]即为子集最小元素,如果这个子集满足要求,那么dp[j-a[i]]即为当前方案数,将其加进答案里即可。
我也太菜了叭,我也太菜了叭,我也太菜了叭…我真的白瞎做那么多背包的题了,当时真的没想到排序这一part,总之菜就完事了
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N = 310;
int a[N];
int dp[N*510];
const int mod = 1e9+7;
bool cmp(int x,int y)
{
return x>y;
}
int main()
{
int t;
cin>>t;
while(t--)
{
int n,m=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]),m+=a[i];
sort(a,a+n,cmp);
memset(dp,0,sizeof dp);
dp[0]=1;
int ans=0;
for(int i=0;i<n;i++)
for(int j=m;j>=a[i];j--)
{
dp[j]=(dp[j]+dp[j-a[i]])%mod;
if(j>=m-j&&j-a[i]<=m-j)
ans=(ans+dp[j-a[i]])%mod;
}
cout<<ans<<endl;
}
return 0;
}