Atcoder Grand Contest 20 C(bitset优化背包)

传送门:

题意:

给你nn个数,现在一共可以形成2n12^{n}-1个集合。他们的和能够形成一个新的数列。现在问你这个新的数列的中位数是多少。

题目分析:

首先需要知道,一个数列的中位数必定是大于等于(i=1nai)/2(sum_{i=1}^{n}a_i)/2,证明如下。

设集合AA能够分为P,QP,Q两个不同的子集,且(PQ=AP igcup Q=A)。此时对于集合P,QP,Q中的所有数,一定有P+Q=Asum P+sum Q=sum A。我们假设PQsum P le sum Q,则有P12Asum P le frac{1}{2}*sum A,同时有Q12Asum Q ge frac{1}{2}*sum A

而又因为集合PQ=AP igcup Q=A,故我们可以假设PP属于AA的前半部分,即:P1=A1,P2=A2P2n11=A2n11P_1=A_1,P_2=A_2 dots P_{2^{n-1}-1}=A_{2^{n-1}-1}。同时Q属于AA的后半部分,即:P2n1=A2n1P2n1=A2n1P_{2^{n-1}}=A_{2^{n-1}} dots P_{2^{n}-1}=A_{2^{n}-1}

因此我们只需要找到第一个大于等于12Afrac{1}{2}sum{A}的数即可。

而这个此时我们的问题即转化为,让你从这个数列中选取一个子序列,使得子序列的和为12Afrac{1}{2}sum{A}。而这个问题我们可以用可达性01背包去解决。

但是如果直接去做,时间复杂度为O(n2max(ai))mathcal{O}(n^2max(a_i)),显然不符合条件。

而考虑到这是一个可达性只有0和1两种状态,因此我们可以用bitset去优化。

故整体的时间复杂度为 O(n2max(ai)64)mathcal{O}(frac{n^2max(a_i)}{64})

代码:

#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
",i);
            return 0;
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/Chen-Jr/p/11007139.html