首页 > 代码库 > poj 3977 Subset 枚举+二分

poj 3977 Subset 枚举+二分

首先分成一半2^17和2^18,并且把其中一半变成相反数,然后枚举一半二分查找另一半,在找到的位置前后也找找。

这里用到了二级排序,有很多细节要处理,不多说了。

巨坑的一个地方就是,不能用系统的abs,要自己手写,简直坑死。。



#include<cstdio>
#include<algorithm>
#include<iostream>
#include<map>
using namespace std;
typedef long long ll;
struct node
{
    int num;
    ll val;
    bool operator <(const node &x) const
    {
        if(val==x.val) return num<x.num;
        return val<x.val;
    }
}a[300000],b[300000];
ll s[100];
int n1,n;
ll ansx;
int ansk;
int top1,top2;
void dfs1(int now,ll sum,int num)
{
    if(now>n1)
    {
        if(num){
        a[top1].val=sum;
        a[top1++].num=num;
        }
        return;
    }
    dfs1(now+1,sum+s[now],num+1);
    dfs1(now+1,sum,num);
}
void dfs2(int now,ll sum,int num)
{
    if(now>n)
    {
        if(num){
        b[top2].val=-sum;
        b[top2++].num=num;
        }
        return;
    }
    dfs2(now+1,sum+s[now],num+1);
    dfs2(now+1,sum,num);
}
ll myabs(ll a)
{
    return a<0?-a:a;
}
int myabs(int a)
{
    return a<0?-a:a;
}
void cal(int p)
{
    node cq;
    cq.val=a[p].val;
    cq.num=0;
    int tmp=lower_bound(b,b+top2,cq)-b;
    ll tzf=myabs(a[p].val-b[tmp].val);
    if(tzf<ansx)
    {
        ansx=tzf;
        ansk=a[p].num+b[tmp].num;
    }
    else if(tzf==ansx)
    {
        ansk=min(ansk,a[p].num+b[tmp].num);
    }

    int fuck=tmp-1;
    if(fuck<0) return;
    cq.val=b[fuck].val;
    cq.num=0;
    tmp=lower_bound(b,b+top2,cq)-b;
    tmp++;

        if(tmp-1>=0)
        {
            tzf=myabs(a[p].val-b[tmp-1].val);
            if(tzf<ansx)
            {
                ansx=tzf;
                ansk=a[p].num+b[tmp-1].num;
            }
            else if(tzf==ansx)
            {
                ansk=min(ansk,a[p].num+b[tmp-1].num);
            }
        }
}
int main()
{
    while(~scanf("%d",&n))
    {
        if(n==0) break;
        int flag=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%I64d",&s[i]);
            if(s[i]==0) flag=1;
        }
        if(flag)
        {
            printf("0 1\n");
            continue;
        }
        top1=top2=0;
        ansx=0x7fffffffffffffffll;
        ansk=0x7ffffff;
        n1=n/2;
        dfs1(1,0,0);

        dfs2(n/2+1,0,0);

        sort(a,a+top1);
        sort(b,b+top2);

        for(int i=0;i<top1;i++)
        {
            if(myabs(a[i].val)<ansx)
            {
                ansx=myabs(a[i].val);
                ansk=a[i].num;
            }
            else if(myabs(a[i].val)==ansx)
            {
                ansk=min(ansk,a[i].num);
            }
        }
        for(int i=0;i<top2;i++)
        {
            if(myabs(b[i].val)<ansx)
            {
                ansx=myabs(b[i].val);
                ansk=b[i].num;
            }
            else if(myabs(b[i].val)==ansx)
            {
                ansk=min(ansk,b[i].num);
            }
        }
        for(int i=0;i<top1;i++)
        {
            cal(i);
        }
        printf("%I64d %d\n",ansx,ansk);
    }
    return 0;
}