【DP】【bitset】17.6.4 均分 题解

来源:互联网 发布:apache jmeter 中文版 编辑:程序博客网 时间:2024/06/16 16:06

这里写图片描述
这里写图片描述
暴力就是做背包,然后找最接近一半的可以凑出来的值
由n<=10^6且sigma a[i]<=10^6我们可以知道不相等的a[i]最多有根号10^6种
那么就从一个10^6个物品的背包变成了10^3个物品的每个物品可以有多个的背包
用二进制拆包优化,复杂度为10^3*10^6*log
用bitset优化,再除以32

事实上可以参考2015年任之洲集训队论文,提出了一种n log n的近似算法,效果也很优秀,审题人并未实现,不过应该可以AC,因为曾经用这个算法AC过其他的带权均分问题

#include<iostream>#include<cstdio>#include<cstdlib>#include<bitset>#include<cstring>#include<string>#include<cmath>#include<algorithm>#define INF_min 1e9using namespace std;int T,n,tot,ans;int a[1000001],cnt[1001];bitset <1000005> bit;int main(){   freopen("share.in","r",stdin);    freopen("share.out","w",stdout);    scanf("%d",&T);    while(T--)    {        bit.reset();tot=0;        memset(cnt,0,sizeof(cnt));        scanf("%d",&n);        bit[0]=1;        for(int i=1;i<=n;i++){scanf("%d",&a[i]);tot+=a[i];}        for(int i=1;i<=n;i++)        {            if(a[i]<sqrt(tot))cnt[a[i]]++;            else bit|=bit<<a[i];        }        int t=1;        for(int i=1;i<=sqrt(tot);i++)        {            t=1;            while(cnt[i])            {                if(cnt[i]>=t)                {                    bit|=bit<<(i*t);                    cnt[i]-=t;                    t*=2;                }                else {bit|=bit<<(cnt[i]*t);cnt[i]=0;}            }        }        ans = INF_min;        for(int i=0;i<=bit.size();i++) if(bit[i]) ans = min(ans, abs(i-(tot-i)));        printf("%d\n",ans);    }    return 0;}
原创粉丝点击