首先分成一半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