题目
洛谷P1466[USACO2.2]集合Subset Sums
题解
此题关键在于将“能划分成几种子集”转化为“有多少子集的和是全集和的一半”。由于和不大,所以可以考虑递推。这个问题的模型是“0/1背包问题”:从一些物品中选取一部分,装满背包。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1000;
int n,sum;
ll f[maxn][40]; //f[i][j]表示1~j的子集中元素和为i的集合的数量
inline void solve()
{
for(int i=0;i<=n;i++) f[0][i]=1; //空集
for(int i=1;i<=sum/2;i++)
{
for(int j=1;j<=n;j++)
{
if(i-j>=0) f[i][j]=f[i-j][j-1]+f[i][j-1]; //1~j的子集分为含j的和不含j的
else f[i][j]=f[i][j-1]; //只能不含j
}
}
printf("%lld\n",f[sum/2][n]/2); //注意答案要除以2,因为两个子集组合成一个全集
}
int main()
{
scanf("%d",&n);
sum=(1+n)*n/2;
if(sum&1) {printf("0\n"); return 0;} //sum为奇数时,无法分成相等两部分
solve();
return 0;
}