您的位置:首页 > 移动开发

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

2017-09-11 23:18 260 查看
题意:给你长度为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 95
using namespace std;
int a
;
vector<int>vt
;
vector<int>::iterator it;
int mi

,ma

;
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);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: