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

传送门:

题意:

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

题目分析:

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

设集合AAA能够分为P,QP,QP,Q两个不同的子集,且(P⋃Q=AP \bigcup Q=APQ=A)。此时对于集合P,QP,QP,Q中的所有数,一定有∑P+∑Q=∑A\sum P+\sum Q=\sum AP+Q=A。我们假设∑P≤∑Q\sum P \le \sum QPQ,则有∑P≤12∗∑A\sum P \le \frac{1}{2}*\sum AP21A,同时有∑Q≥12∗∑A\sum Q \ge \frac{1}{2}*\sum AQ21A

而又因为集合P⋃Q=AP \bigcup Q=APQ=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=A2P2n11=A2n11。同时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}P2n1=A2n1P2n1=A2n1

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

而这个此时我们的问题即转化为,让你从这个数列中选取一个子序列,使得子序列的和为12∑A\frac{1}{2}\sum{A}21A。而这个问题我们可以用可达性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;
}

转载于:https://www.cnblogs.com/Chen-Jr/p/11007139.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值