传送门:
题意:
给你nnn个数,现在一共可以形成2n−12^{n}-12n−1个集合。他们的和能够形成一个新的数列。现在问你这个新的数列的中位数是多少。
题目分析:
首先需要知道,一个数列的中位数必定是大于等于(∑i=1nai)/2(\sum_{i=1}^{n}a_i)/2(∑i=1nai)/2,证明如下。
设集合AAA能够分为P,QP,QP,Q两个不同的子集,且(P⋃Q=AP \bigcup Q=AP⋃Q=A)。此时对于集合P,QP,QP,Q中的所有数,一定有∑P+∑Q=∑A\sum P+\sum Q=\sum A∑P+∑Q=∑A。我们假设∑P≤∑Q\sum P \le \sum Q∑P≤∑Q,则有∑P≤12∗∑A\sum P \le \frac{1}{2}*\sum A∑P≤21∗∑A,同时有∑Q≥12∗∑A\sum Q \ge \frac{1}{2}*\sum A∑Q≥21∗∑A。
而又因为集合P⋃Q=AP \bigcup Q=AP⋃Q=A,故我们可以假设PPP属于AAA的前半部分,即:P1=A1,P2=A2…P2n−1−1=A2n−1−1P_1=A_1,P_2=A_2 \dots P_{2^{n-1}-1}=A_{2^{n-1}-1}P1=A1,P2=A2…P2n−1−1=A2n−1−1。同时Q属于AAA的后半部分,即:P2n−1=A2n−1…P2n−1=A2n−1P_{2^{n-1}}=A_{2^{n-1}} \dots P_{2^{n}-1}=A_{2^{n}-1}P2n−1=A2n−1…P2n−1=A2n−1。
因此我们只需要找到第一个大于等于12∑A\frac{1}{2}\sum{A}21∑A的数即可。
而这个此时我们的问题即转化为,让你从这个数列中选取一个子序列,使得子序列的和为12∑A\frac{1}{2}\sum{A}21∑A。而这个问题我们可以用可达性01背包去解决。
但是如果直接去做,时间复杂度为O(n2max(ai))\mathcal{O}(n^2\max(a_i))O(n2max(ai)),显然不符合条件。
而考虑到这是一个可达性只有0和1两种状态,因此我们可以用bitset去优化。
故整体的时间复杂度为 O(n2max(ai)64)\mathcal{O}(\frac{n^2\max(a_i)}{64})O(64n2max(ai))
代码:
#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;
}