这个题35的数据还是比较大,不过把它分为2堆进行枚举就可以承受了,比较狠的是abs需要自己手写,否则WA
代码:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
const long long inf=1LL<<60;
const int maxn=40;
const int maxm=1<<18;
struct Node
{
long long sum;
int num;
Node(){}
Node(long long sm,int snum):sum(sm),num(snum){}
bool operator < (const Node &a)const
{
return sum<a.sum;
}
}SA[maxm],S[maxm];
int n,m,cnt,ansn;
long long a[maxn],ans;
vector<long long> A,B;
int cmp(Node a,Node b)
{
if(a.sum==b.sum)
return a.num<b.num;
return a.sum<b.sum;
}
long long Abs(long long val)
{
if(val<0)
return -val;
return val;
}
void InitSetA()
{
int up=1<<m;
for(int i=1;i<up;i++)
{
SA[i].sum=SA[i].num=0;
for(int j=0;j<m;j++)
if((i>>j)&1)
{
SA[i].sum+=A[j];
SA[i].num++;
}
if(Abs(SA[i].sum)<ans)
{
ans=Abs(SA[i].sum);
ansn=SA[i].num;
}
else if(Abs(SA[i].sum)==ans)
{
ansn=min(ansn,SA[i].num);
}
}
sort(SA+1,SA+up,cmp);
cnt=0;
S[cnt++]=SA[1];
for(int i=2;i<up;i++)
if(SA[i].sum!=SA[i-1].sum)
S[cnt++]=SA[i];
}
void GetAns()
{
int up=1<<(n-m),res=n-m,num;
long long sum;
for(int i=1;i<up;i++)
{
sum=num=0;
for(int j=0;j<res;j++)
if((i>>j)&1)
{
sum+=B[j];
num++;
}
if(Abs(sum)<ans)
{
ans=Abs(sum);
ansn=num;
}
else if(Abs(sum)==ans)
{
ansn=min(ansn,num);
}
int index=lower_bound(S,S+cnt,Node(-sum,num))-S;
if(index<cnt)
{
if(Abs(sum+S[index].sum)<ans)
{
ans=Abs(sum+S[index].sum);
ansn=num+S[index].num;
}
else if(Abs(sum+S[index].sum)==ans)
ansn=min(ansn,num+S[index].num);
}
if(index>0)
{
if(Abs(sum+S[index-1].sum)<ans)
{
ans=Abs(sum+S[index-1].sum);
ansn=num+S[index-1].num;
}
else if(Abs(sum+S[index-1].sum)==ans)
ansn=min(ansn,num+S[index-1].num);
}
}
}
int main()
{
while(scanf("%d",&n)&&n)
{
ans=inf;
ansn=0;
for(int i=0;i<n;i++)
scanf("%I64d",&a[i]);
m=(n+1)/2;
A.clear();
B.clear();
for(int i=0;i<n;i++)
{
if(i<m)
A.push_back(a[i]);
else
B.push_back(a[i]);
}
InitSetA();
GetAns();
printf("%I64d %d\n",ans,ansn);
}
return 0;
}