hdu 3017 Treasure Division 折半枚举 + 双指针

来源:互联网 发布:淘宝手机详情页装修 编辑:程序博客网 时间:2024/05/23 13:55

运气不错排了第二。内存比他们大了好多。不知道他们是什么方法。


把n个coin分成两半,在两半里分别枚举所有情况,第一半取了i枚硬币则把价值存入s1[i],第二半取了i枚硬币则把价值存入s2[i]。时间复杂度2 × 2^(n/2 ) 。然后都排序。

假设所有硬币总价值为sum,aim = sum/2.  

最后要把硬币都分成两部分,我们只求价值小的那部分。所以这个要求的 一定小于等于aim,并且越大越优

枚举s1中的所有情况,在s2中找对应最优的,用双指针


#pragma comment(linker, "/STACK:102400000,102400000")#include<stdio.h>#include<string.h>#include<ctype.h>#include<math.h>#include<string>#include<vector>#include<map>#include<queue>#include<set>#include<algorithm>using namespace std;void fre(){freopen("t.txt","r",stdin);}#define ls o<<1#define rs o<<1|1#define MS(x,y) memset(x,y,sizeof(x))#define MC(x,y) memcpy(x,y,sizeof(y))template <class T1, class T2>inline void gmax(T1 &a, T2 b) { if (b>a)a = b; }template <class T1, class T2>inline void gmin(T1 &a, T2 b) { if (b<a)a = b; }typedef long long LL;typedef unsigned long long UL;typedef unsigned int UI;const int INF = 0x3f3f3f3f ;const double pi = acos(-1.0);const int MAXN = 100010;const LL M = 20090818;int n,mid,c1[16],c2[16];;LL a[35],ans,sum,s1[16][35000],s2[16][35000],aim;void dfs1(int s,LL sum,int l){    s1[s][c1[s]++] = sum;    for(int i = l; i < mid; ++i)        dfs1(s+1,sum+a[i],i+1);}void dfs2(int s,LL sum,int l){    s2[s][c2[s]++] = sum;    for(int i = l; i < n; ++i)        dfs2(s+1,sum+a[i],i+1);}void solve(){    ans = sum = 0;    MS(c1,0);MS(c2,0);    for(int i = 0; i < n; ++i)        scanf("%lld",&a[i]),sum += a[i];    mid = n/2;    dfs1(0,0,0);dfs2(0,0,mid);    for(int i = 1; i <= 15; ++i)        sort(s1[i],s1[i]+c1[i]),sort(s2[i],s2[i]+c2[i]);    aim = sum/2;    int tem,k;    for(int i = 0; i <= mid; ++i)    {        tem = mid-i; k = c2[tem]-1;        for(int j = 0; j < c1[i]; ++j)        {            while(s1[i][j]+s2[tem][k]>aim && k>0) k--;            if(s1[i][j]+s2[tem][k]>aim) break;            gmax(ans,s1[i][j]+s2[tem][k]);        }        if(n&1)        {            tem++; k = c2[tem]-1;            for(int j = 0; j < c1[i]; ++j)            {                while(s1[i][j]+s2[tem][k]>aim && k>0) k--;                if(s1[i][j]+s2[tem][k]>aim) break;                gmax(ans,s1[i][j]+s2[tem][k]);            }        }    }    printf("%lld\n",sum-2*ans);}int main(){    //fre();    while(~scanf("%d",&n))        solve();    return 0;}


1 0
原创粉丝点击