您的位置:首页 > 其它

【BZOJ】1187: [HNOI2007]神奇游乐园

2017-02-21 21:40 260 查看
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1187

每个格子都具有权值,求任意一个回路使得路径上的权值和最大。

裸的插头DP,注意一下几点:

1.因为不一定要全部格子都要走过,所以可以空一格不走,前提这个状态是没有上插头和左插头的。

2.每个格子都应该可以作为起始状态(新建连通块)。

3.关于形成回路的状态显然不能再往下转移,同时如果这个的轮廓线上除了左插头和右插头之外没有插头了,可以算入答案。

QwQ...细节还是看代码吧。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<cstring>
using namespace std;
#define maxn 10010
#define llg long long
#define sizee 57
#define maxZT (1<<18)
#define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
llg n,m,now,size[2],zt[2][maxZT],ans,la,code[maxn],quan;
llg v[2][maxZT];

struct node
{
llg x,val,pos;
};

vector<node>a[2][sizee];

void outcode(llg x) {for (llg i=0;i<=m;i++) code[i]=x&3,x>>=2;}

void encode(llg p,llg val)
{
llg x=0;
for (llg i=0;i<=m;i++) x+=code[i]*(1<<(i*2));
llg wz=x%sizee,E=a[p][wz].size();
for (llg i=0;i<E;i++)
if (a[p][wz][i].x==x)
{
a[p][wz][i].val=max(a[p][wz][i].val,val);
v[p][a[p][wz][i].pos]=max(v[p][a[p][wz][i].pos],val);
return ;
}
size[p]++;
node NEW; NEW.x=x; NEW.val=val; NEW.pos=size[p];
a[p][wz].push_back(NEW);
zt[p][size[p]]=x; v[p][size[p]]=val;
}

void init_a(llg p){for (llg i=0;i<sizee;i++) a[p][i].clear(); size[p]=0;}

void DP()
{
llg now=0;
encode(0,0);
for (llg i=1;i<=n;i++)
{
for (llg k=1;k<=size[now];k++) zt[now][k]*=4;
for (llg j=1;j<=m;j++)
{
scanf("%lld",&quan);
now^=1; la=now^1; size[now]=0;
init_a(now);
for (llg k=1;k<=size[la];k++)
{
outcode(zt[la][k]);
llg le=code[j-1],up=code[j],V=v[la][k];

if (!le && !up) //空格
{
encode(now,V);
}
//-------------------------------------------------------------------------------------
if (!le && !up)//没有插头,新建连通分量
{
if (j<m)
{
code[j-1]=1,code[j]=2;
encode(now,V+quan);
}
continue;
}
//-------------------------------------------------------------------------------------
if (!le && up)//延续上插头
{
if (j<m) encode(now,V+quan);
code[j-1]=code[j]; code[j]=0;
encode(now,V+quan);
continue;
}
//-------------------------------------------------------------------------------------
if (le && !up)//延续左插头
{
encode(now,V+quan);
if (j<m)
{
code[j]=code[j-1]; code[j-1]=0;
encode(now,V+quan);
}
continue;
}
//-------------------------------------------------------------------------------------
if (le==1 && up==2)//回路闭合,统计答案
{
bool pd=true;
for (llg e=0;e<j-1;e++) if (code[e]) pd=false;
for (llg e=j+1;e<=m;e++) if (code[e]) pd=false;
if (pd) ans=max(ans,V+quan);
//        if (pd) cout<<i<<" "<<j<<"--->"<<V+quan<<endl;
continue;
}
//-------------------------------------------------------------------------------------
if (le==2 && up==1)//左插头为右括号,上插头为左括号,直接合并
{
code[j]=code[j-1]=0;
encode(now,V+quan);
continue;
}
//-------------------------------------------------------------------------------------
if (le==1 && up==1)//上左插头均为左括号,找到上插头所对应的右括号并将其修改为左括号
{
for (llg e=j+1;e<=m;e++)
if (code[e]==2)
{
code[e]=1;
break;
}
code[j]=code[j-1]=0;
encode(now,V+quan);
continue;
}
//-------------------------------------------------------------------------------------
if (le==2 && up==2)//上左插头均为右括号,找到左插头对应的左括号并将其修改为右括号
{
for (llg e=j-2;e>=0;e--)
if (code[e]==1)
{
code[e]=2;
break;
}
code[j]=code[j-1]=0;
encode(now,V+quan);
continue;
}
}
}
}
}

int main()
{
yyj("a");
ans=-1*0x7fffffff;
cin>>n>>m;
DP();
cout<<ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: