折半搜索。
学到了map.lower_bound;搜索map[i]的i的大小,返回第一个大于等于i的map值。
先做前面再做后面,就是基本的折半搜索,难点在于如何去处理,不能为空集。
这里我每一次状态都是从1开始,表示从不为空。
然后单独再每一半搜索中,更新一下最值。
然后再合起来更新。min函数可以用于pair!
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<climits>
#include<stack>
#include<vector>
#include<queue>
#include<set>
#include<map>
#define up(i,a,b) for(int i=a;i<b;i++)
#define dw(i,a,b) for(int i=a;i>b;i--)
#define upd(i,a,b) for(int i=a;i<=b;i++)
#define dwd(i,a,b) for(int i=a;i>=b;i--)
//#define local
typedef long long ll;
const double esp = 1e-6;
const double pi = acos(-1.0);
const long long INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int, int> pir;
int n;
ll a[40];
ll abs1(ll sum)
{
if (sum < 0)
return -sum;
else return sum;
}
pair<ll,int> solve()
{
int mid = n / 2;
ll ng=0;
int cnt = 0;
pair<ll, int > res = make_pair(abs1(a[0]), 1);
map<ll, int> mp;
up(i, 1, (1<<mid))
{
ng = 0;
cnt = 0;
up(j, 0, mid)
{
if (i >> j & 1)
{
ng+= a[j];
cnt++;
}
}
res = min(res, make_pair(abs1(ng), cnt));
if (mp[ng] != 0)
{
mp[ng] = min(mp[ng], cnt);
}
else
{
mp[ng] = cnt;
}
}
up(i, 1, (1 << (n - mid)))
{
ng = 0;
cnt = 0;
up(j, 0, (n - mid))
{
if (i >> j & 1)
{
ng += a[mid + j];
cnt++;
}
}
res = min(res, make_pair(abs1(ng), cnt));
map<ll, int>::iterator it = mp.lower_bound(-ng);
if (it != mp.end())
{
res = min(res, make_pair(abs1(it->first + ng), it->second + cnt));
}
if (it != mp.begin())
{
it--;
res = min(res, make_pair(abs1(it->first + ng), it->second + cnt));
}
}
return res;
}
int main() {
while (cin >> n && n)
{
up(i, 0, n)
{
scanf("%lld", &a[i]);
}
pair<ll,int> ans = solve();
cout << ans.first<<" "<< ans.second<<endl;
}
return 0;
}