Atcoder Grand Contest 20 C(bitset优化背包)
传送门:
题意:
给你个数,现在一共可以形成个集合。他们的和能够形成一个新的数列。现在问你这个新的数列的中位数是多少。
题目分析:
首先需要知道,一个数列的中位数必定是大于等于,证明如下。
设集合能够分为两个不同的子集,且()。此时对于集合中的所有数,一定有。我们假设,则有,同时有。
而又因为集合,故我们可以假设属于的前半部分,即:。同时Q属于的后半部分,即:。
因此我们只需要找到第一个大于等于的数即可。
而这个此时我们的问题即转化为,让你从这个数列中选取一个子序列,使得子序列的和为。而这个问题我们可以用可达性01背包去解决。
但是如果直接去做,时间复杂度为,显然不符合条件。
而考虑到这是一个可达性只有0和1两种状态,因此我们可以用bitset去优化。
故整体的时间复杂度为
代码:
#include <bits/stdc++.h>
#define maxn 30
using namespace std;
bitset<maxn>bit;
typedef long long ll;
int main()
{
int n;
scanf("%d",&n);
int sum=0;
bit[0]=1;
for(int i=1;i<=n;i++){
int num;
scanf("%d",&num);
sum+=num;
bit|=bit<<num;
}
int j=(sum+1)>>1;
for(int i=j;i<=sum;i++){
if(bit[i]){
printf("%d\n",i);
return 0;
}
}
return 0;
}