atcoder Median Sum题解

原题链接:https://atcoder.jp/contests/agc020/tasks/agc020_c
上来先给AC代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5;
bitset<N>V;
int main()
{
    int n,s=0;
    scanf("%d",&n);
    V[0]=1;
    for(int i=0,x; i<n; i++)scanf("%d",&x),s+=x,V|=V<<x;
    for(int i=s>>1;;i--)
    if(V[i])
    {
        printf("%d\n",s-i);
        return 0;
    }
}

相信大部分人看不懂的部分在于那个V|=V<<x;语句,这里我给大家详细讲解下。
首先我们定义子集的权值=子集所有元素之和
再定义bitset数组,bit【any】=1,就代表存在一个子集,他的权值为any。bitset数组不懂的可以去百度一下。
bitset[0]=1;他的含义是这个集合存在一个子集,这个子集的权值为0(虽然题目没有空子集,但为了运算简便我们还是将其定义出来),bitset[x]=1的含义是,权值为x的子集存在。

  • 现在,加入一个数x,可以看到原先集合的子集为{∅},现在的集合为{x},子集为{∅},{x}。
  • 那么现在子集的权值分别为0,x。可以看出来,多出来的权值是在原先权值的基础上加新加入的数x。(看不懂不用急,等下还会有例子)
  • 那么我们队bitset数组进行移位操作,因为bitset[0]=1,所有左移x位后bitset[x]=1,代表这现在集合中存在一个子集,它的权值为x
  • 再加入一个数y,之前所有子集的权值分别为0,x。现在新的集合的所有子集的权值分别为,0,x,0+y,x+y。即新的子集的权值是在原子集的权值基础上加上数y的。那么对bitset进行左移y位的操作,因为bitset[0]=1,bitset[x]=1,所有bitset[0+y]=1,bitset[x+y]=1。这就代表着存在子集,他们的权值分别为y与x+y。
  • 但是我们不能忘记,之前的子集{∅},{x}依然存在,所有我们将左移后的结果与原先的bitset数组进行或运算,这样子的话bitset[0],bitset[x],bitset[0+y],bit[x+y]的值就都为1了。意味着该集合的所有子集的权值分别为0,x,y,x+y;

所以我们就能得出所有子集的权值,并将其存储在bitset数组上。

接下来是寻找中位数, 首先对于任何一个集合A, 我们都能找到他的一个对应的补集,这个补集也是B集合中的一个子集,sum=B集合所有元素之和。sum/2后出现的一个数就是中位数(因为空集合是不存在的)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值