HDU 6196 happy happy happy [折半暴搜+剪枝+DP]

来源:互联网 发布:淘宝食品类目 编辑:程序博客网 时间:2024/06/05 10:43

题意:给你长度为n的序列,爸爸和儿子玩一个游戏,儿子先手,儿子每次都选择最左边与最右边最大的那个拿走(若左右相等拿左边),爸爸可以任意拿最左边或者最右边。

题解:

①对于这道题n只有90,我们可以先折半,将前半段与后半段分开考虑,预处理后半段暴力结果,然后dfs(l,r,cha)(表示当前搜到区间[l,r]时候的差值)暴搜前半段情况,对于搜索到区间大小等于后半段操作长度的时候,我们对于当前差值cha在后半段预处理的结果中lower_bound最优答案。我这里选择后半段长度为32,(再长就T了= =)。

②由于前半段完全暴搜肯定爆时间,于是我们加入剪枝。

首先我们要预处理所有区间能得到的最大值差值与最小差值。之后

剪枝:①对于当前区间[l,r],假如当前差值+mindif[l,r]>=0,说明继续搜下去不可能有解,直接return;

   ②对于当前区间[l,r],假如当前差值+maxdif[l,r]<=ans,那说明继续做下去得到的解肯定比ans小,差值更大,也直接return;

   ③对于当前区间[l,r],假如当前差值+maxdif[l,r]<0,那我们直接可以更新答案,然后return;

③那接下来我们如何得到所有区间的最值呢,我们考虑dp

枚举所有区间,先将儿子的选择消去。然后考虑爸爸的转移(ll,rr为转移之后的l与r):

mindif[l][r]=min(mindif[l][r],a[ll]+mindif[ll+1][rr]-sub);
mindif[l][r]=min(mindif[l][r],a[rr]+mindif[ll][rr-1]-sub);
maxdif[l][r]=max(maxdif[l][r],a[ll]+maxdif[ll+1][rr]-sub);

maxdif[l][r]=max(maxdif[l][r],a[rr]+maxdif[ll][rr-1]-sub);

之后我们就可以得到答案了

AC代码:

#include<stdio.h>#include<vector>#include<string.h>#include<algorithm>#include<map>#include<time.h>#define N 95using namespace std;int a[N];vector<int>vt[N];vector<int>::iterator it;int mi[N][N],ma[N][N];int ans,n,hou;map<int,int>mp;void init()  {      for(int i=0;i<N;i++)for(int j=i;j<N;j++){mi[i][j]=(int)1e9;ma[i][j]=(int)-1e9;}     for(int l=n;l>=1;--l)      {          for(int r=l;r<=n;++r)          {              int ll=l,rr=r;              int sub;              if(a[ll]>=a[rr])sub=a[ll++];              else sub=a[rr--];              ma[l][r]=max(ma[l][r],a[ll]+ma[ll+1][rr]-sub);              mi[l][r]=min(mi[l][r],a[ll]+mi[ll+1][rr]-sub);              ma[l][r]=max(ma[l][r],a[rr]+ma[ll][rr-1]-sub);              mi[l][r]=min(mi[l][r],a[rr]+mi[ll][rr-1]-sub);          }      }  }  void dfs(int l,int r,int cha){if(r-l+1==hou*2){it=lower_bound(vt[l].begin(),vt[l].end(),-cha);if(it==vt[l].end()||*it==-cha){if(it==vt[l].begin())return ;else it--;}if(cha+*it<0)ans=max(ans,cha+*it);return ;}if(mi[l][r]+cha>=0)return ;if(ma[l][r]+cha<=ans)return ;if(ma[l][r]+cha<0){ans=max(ans,ma[l][r]+cha);return ;}int sub;if(a[l]>=a[r])sub=a[l++];      else sub=a[r--];    dfs(l+1,r,cha+a[l]-sub);    dfs(l,r-1,cha+a[r]-sub);}int main(){    int t=clock();    while(~scanf("%d",&n))    {        for(int i=0;i<N;i++)vt[i].clear();        for(int i=1;i<=n;i++)            scanf("%d",&a[i]);        if(n==2)        {        if(a[1]==a[2])printf("The child will be unhappy...\n");        else printf("%d\n",max(a[1],a[2])-min(a[1],a[2]));continue ;        }        init();        hou=min(16,n/4),ans=(int)-1e9;        for(int i=1;i+hou*2-1<=n;i++)        {        mp.clear();for(int state=0;state<(1<<hou);state++)        {            int sum=0,l=i,r=l+2*hou-1;            for(int j=0;j<hou;j++)            {                if(a[l]>=a[r])sum-=a[l++];                else sum-=a[r--];                if(!(state&(1<<j)))sum+=a[l++];                else sum+=a[r--];            }            if(mp[sum]==0)            {vt[i].push_back(sum);mp[sum]=1;            }        }        sort(vt[i].begin(),vt[i].end());        }        dfs(1,n,0);        if(ans==(int)-1e9)printf("The child will be unhappy...\n");        else printf("%d\n",-ans);    }}





原创粉丝点击