首先分成一半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;
}
poj 3977 Subset 枚举+二分,布布扣,bubuko.com
原文:http://blog.csdn.net/t1019256391/article/details/26170577