传送门

大概是算第一道自己做出来的插头dp?

(虽然都是照着抄板子的)

(虽然有个地方死活没调出来最后只能看题解才发现自己错在哪里的)

我就当你们都会插头dp了……

因为必须得是一条路径,所以扫描线上的插头得两两对应,要用括号序列

然后分情况讨论一下,记$p1$为当前关键格左边的插头,$p2$为当前关键格上面的插头

$0$表示无插头,$1$表示左括号,$2$表示右括号

1.$p1==0$且$p2==0$

那么很明显我们可以把下方插头设为$1$右方插头设为$2$,就形成一个新的连通块了

然后注意不设任何插头的状态也要转移(我就是在这里坑了一个晚上)

2.$p1!=0$且$p2==0$

那么我们有两种走法,一是直走,那么右插头的值就是原插头的值,一是拐弯,那么下面的插头的值就是左插头的值

3.$p1==0$且$p2!=0$

同上,不多说了

4.$p1==1$且$p2==1$

就是两个左括号撞到一起了,那么把$p2$对应的右括号改成左括号

5.$p1==1$且$p2==2$

这种情况就说明一条路径已经结束了,那么此时如果轮廓线上没有其他任何插头就可以更新答案了

6.$p1==2$且$p2==1$

两条路径在这里汇合,直接合并

7.$p1==2$且$p2==2$

两个右括号撞到一起了,那么把$p1$对应的左括号改成右括号

然后……剩下的看代码好了(似乎我的插头dp写法和很多人不一样诶……)

 //minamoto
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,:;}
const int mod=;
int n,m,c[][];ll ans=-0x3f3f3f3f3f3f3f3f;
struct Ha{
int key[mod],sz,Hash[mod];ll val[mod];
inline void init(){
memset(val,0xef,sizeof(val)),memset(key,-,sizeof(key));
sz=,memset(Hash,,sizeof(Hash));
}
inline void newhash(int id,int state){Hash[id]=++sz,key[sz]=state,val[sz]=-inf;}
ll &operator [](const int state){
for(int i=state%mod;;i=(i+==mod)?:i+){
if(!Hash[i]) newhash(i,state);
if(key[Hash[i]]==state) return val[Hash[i]];
}
}
}f[];
inline int find(int state,int id){return (state>>((id-)<<))&;}
inline void set(int &state,int pos,int val){
pos=(pos-)<<,state|=<<pos,state^=<<pos,state|=val<<pos;
}
int link(int state,int pos){
int cnt=,del=(find(state,pos)==)?:-;
for(int i=pos;i&&i<=m+;i+=del){
int plug=find(state,i);
if(plug==) ++cnt;
else if(plug==) --cnt;
if(!cnt) return i;
}
return -;
}
void solve(int x,int y){
int now=((x-)*m+y)&,last=now^,tot=f[last].sz;
f[now].init();
for(int i=;i<=tot;++i){
int state=f[last].key[i];ll val=f[last].val[i];
int plug1=find(state,y),plug2=find(state,y+);
if(!plug1&&!plug2){
cmax(f[now][state],val);
if(x!=n&&y!=m) set(state,y,),set(state,y+,),cmax(f[now][state],val+c[x][y]);
}
else if(plug1&&!plug2){
if(x!=n) cmax(f[now][state],val+c[x][y]);
if(y!=m) set(state,y,),set(state,y+,plug1),cmax(f[now][state],val+c[x][y]);
}
else if(!plug1&&plug2){
if(y!=m) cmax(f[now][state],val+c[x][y]);
if(x!=n) set(state,y,plug2),set(state,y+,),cmax(f[now][state],val+c[x][y]);
}
else if(plug1==&&plug2==)
set(state,link(state,y+),),set(state,y,),set(state,y+,),cmax(f[now][state],val+c[x][y]);
else if(plug1==&&plug2==){
set(state,y,),set(state,y+,);
if(!state) cmax(ans,val+c[x][y]);
}
else if(plug1==&&plug2==) set(state,y,),set(state,y+,),cmax(f[now][state],val+c[x][y]);
else if(plug1==&&plug2==)
set(state,link(state,y),),set(state,y,),set(state,y+,),cmax(f[now][state],val+c[x][y]);
}
}
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d",&n,&m);
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
scanf("%d",&c[i][j]);
f[].init(),f[][]=;
for(int i=;i<=n;++i){
for(int j=;j<=m;++j) solve(i,j);
if(i!=n){
int now=(i*m)&,tot=f[now].sz;
for(int j=;j<=tot;++j)
f[now].key[j]<<=;
}
}
printf("%lld\n",ans);
return ;
}

洛谷P3190 [HNOI2007]神奇游乐园(插头dp)的更多相关文章

  1. 洛谷 P3190 [HNOI2007]神奇游乐园 解题报告

    P3190 [HNOI2007]神奇游乐园 Description 给你一个 \(m * n\) 的矩阵,每个矩阵内有个权值\(V(i,j)\) (可能为负数),要求找一条回路,使得每个点最多经过一次 ...

  2. bzoj 1187: [HNOI2007]神奇游乐园 插头dp

    1187: [HNOI2007]神奇游乐园 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 668  Solved: 337[Submit][Statu ...

  3. 【BZOJ1187】[HNOI2007]神奇游乐园 插头DP

    [BZOJ1187][HNOI2007]神奇游乐园 Description 经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细 ...

  4. [HNOI2007][bzoj1187] 神奇游乐园 [插头dp]

    题面: 传送门 给定一个四联通棋盘图,每个格子有权值,求一条总权值最大的回路 思路: 插头dp基础教程 棋盘? 回路? n,m<=10? 当然是插头dp啦~\(≧▽≦)/~ 然后发现这道题并不是 ...

  5. P3190 [HNOI2007]神奇游乐园

    传送门 第一道插头 $dp$ 由于讲不清楚所以假装各位早就会插头 $dp$ 了 首先要的是一个闭合回路,所以可以用括号表示法表示状态,然后大力分类讨论 $1.$ 没有右插头和下插头 那么我们可以啥也不 ...

  6. 洛谷P3272 [SCOI2011]地板(插头dp)

    传送门 感谢大佬的教导->这里 容易注意到,本题的合法路径“L型地板”有一些特殊的地方:拐弯且仅拐弯一次. 这由于一条路径只有两种状态:拐弯过和没拐弯过,因此我们可以尝试着这样定义新的插头: 我 ...

  7. 洛谷P2289 [HNOI2004]邮递员(插头dp)

    传送门 太神仙了……讲不来讲不来->这里 //minamoto #include<iostream> #include<cstdio> #include<cstri ...

  8. [bzoj1187][HNOI2007]神奇游乐园_插头dp

    bzoj-1187 HNOI-2007 神奇游乐园 题目大意:经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这 ...

  9. 洛谷P2507 [SCOI2008]配对 题解(dp+贪心)

    洛谷P2507 [SCOI2008]配对 题解(dp+贪心) 标签:题解 阅读体验:https://zybuluo.com/Junlier/note/1299251 链接题目地址:洛谷P2507 [S ...

随机推荐

  1. 在pycharm中执行脚本没有报错但输出显示Redirection is not supported.

    没有新式语法错误,但是输出显示Redirection is not supported.(不支持重定向) 在stockflow中找到是因为从IDE中运行脚本的原因,比如pycharm,所有IDE都提供 ...

  2. 电话聊天狂人 【STL】

    7-2 电话聊天狂人(25 分) 给定大量手机用户通话记录,找出其中通话次数最多的聊天狂人. 输入格式: 输入首先给出正整数N(≤10​5​​),为通话记录条数.随后N行,每行给出一条通话记录.简单起 ...

  3. 在datax之前版本中添加filewriter并创建job时出现问题

    问题描述:

  4. PYTHON 爬虫笔记七:Selenium库基础用法

    知识点一:Selenium库详解及其基本使用 什么是Selenium selenium 是一套完整的web应用程序测试系统,包含了测试的录制(selenium IDE),编写及运行(Selenium ...

  5. html的head中的常见元素

    <head></head>中有charset, title,link 操作系统默认的字符编码就是gbk. html的加强 (1)<a href="#" ...

  6. 使用 DNSPOD API 实现域名动态解析

    0. 简单概述在家里放一个 NAS 服务器,但是宽带的 IP 地址经常改变,一般路由器自带的花生壳域名解析可以解决,如果路由器没有类似功能或者想使用自己的域名,可以尝试使用 DNSPOD API 来实 ...

  7. Hotel California

    On a dark desert highway行驶在昏黑的荒漠公路上cool wind in my hair凉风吹过我的头发warm smell of colutas温馨的大麻香rising up ...

  8. C语言中的指针(二)

    指针指向谁,就把谁的地址赋给指针,指针变量和指针指向的内存变量是不一样的.不停的给指针赋值,相当于是不断的改变指针的指向. 在开发中要避免野指针的存在,在指针使用完毕之后,记得要给指针赋值成为NULL ...

  9. HihoCoder1649 : 漏写的数字([Offer收割]编程练习赛38)(模拟题)

    描述 小A今年刚上幼儿园,正在学习写100以内的数字.幼儿园的老师留了一项作业,要求小A从某个100以内的数X开始一直写到另一个100以内的数Y(Y - X > 1). 不过粗心的小A在作业中漏 ...

  10. 百度地图API的第一次接触——地图事件

    0.初始化地图 var map = new BMap.Map("container"); var point = new BMap.Point(116.404, 39.915); ...