传送门

第一道插头 $dp$

由于讲不清楚所以假装各位早就会插头 $dp$ 了

首先要的是一个闭合回路,所以可以用括号表示法表示状态,然后大力分类讨论

$1.$ 没有右插头和下插头

那么我们可以啥也不干,或者加一个右插头和下插头

$2.$ 只有下插头没有右插头

那么我们可以要把下插头继续延伸,可以向下或者向右

$3.$ 只有右插头没有下插头:

同理我们可以往下或者往右延伸

$4.$ 右插头和下插头都有:这个又要分情况讨论

  $a.$ 插头都是左括号,那么要把两个联通还要把右边原来匹配的右括号改成左括号

  

  $b.$ 插头都是右括号,那么要把两个联通还要把左边原本匹配的左括号改成右括号

  

  $c.$ 右插头是左括号,下插头是右括号,那么直接联通即可,不需要改变其他括号

  

  $d.$ 右插头是右括号,下插头是左括号,如果联通则一定形成一个闭合回路,那么如果其他地方没有插头则直接把当前状态计入答案,否则此状态不合法,不用延伸状态(右图是一种不合法状态)

  

然后根据考虑到的所有状态慢慢转移即可......

因为数据比较大所以用滚动数组和哈希表维护状态,状态在加入哈希表时更新

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=3e5;
const ll INF=1e18;
int n,m,a[][],bit[],cur,pre;
ll f[][N+],Ans=-INF;
int fir[N+],from[N+],to[][N+],cntt[];//哈希表
inline void insert(int sta,ll val)//插入状态并更新f
{
int p=sta%N;
for(int i=fir[p];i;i=from[i])
{
if(to[cur][i]!=sta) continue;
f[cur][i]=max(f[cur][i],val); return;
}
from[++cntt[cur]]=fir[p]; fir[p]=cntt[cur];
to[cur][cntt[cur]]=sta; f[cur][cntt[cur]]=val;
}
void DP()
{
cntt[cur]=; int now,down,right; ll val;
for(int i=;i<=n;i++)//枚举行
{
for(int j=;j<=cntt[cur];j++) to[cur][j]<<=;//每一行末尾,状态统一左移四进制下的一位
for(int j=;j<=m;j++)//枚举列
{
pre=cur; cur^=; cntt[cur]=; memset(fir,,sizeof(fir));//清空哈希表
for(int k=;k<=cntt[pre];k++)//枚举上一行的状态
{
now=to[pre][k]; val=f[pre][k];
right=(now>>bit[j-])%; down=(now>>bit[j])%;//提出插头状态
if(!down&&!right)//没有插头
{
insert(now,val);//继续没有插头
if(j!=m) insert(now+(<<bit[j-])+((<<bit[j])<<),val+a[i][j]);//多一个右插头和下插头
}
if(down&&!right)//只有下插头
{
insert(now-down*(<<bit[j])+down*(<<bit[j-]),val+a[i][j]);//向下延伸
if(j!=m) insert(now,val+a[i][j]);//向右延伸
}
if(!down&&right)//只有右插头
{
insert(now,val+a[i][j]);//向下延伸
if(j!=m) insert(now-right*(<<bit[j-])+right*(<<bit[j]),val+a[i][j]);//向右延伸
}
if(down==&&right==)//插头为'(('
{
int cnt=;
for(int l=j+;l<=m;l++)//找到右边第一个和当前下插头匹配的')'
{
if((now>>bit[l])%==) cnt++;
if((now>>bit[l])%==) cnt--;
if(!cnt)
{
insert(now-(<<bit[l])-(<<bit[j-])-(<<bit[j]),val+a[i][j]);//联通并改')'为'('
break;
}
}
}
if(down==&&right==)//插头为'))'
{
int cnt=;
for(int l=j-;l>=;l--)//找到左边第一个和当前右插头匹配的'('
{
if((now>>bit[l])%==) cnt--;
if((now>>bit[l])%==) cnt++;
if(!cnt)
{
insert(now+(<<bit[l])-((<<bit[j-])<<)-((<<bit[j])<<),val+a[i][j]);//联通并改'('为')'
break;
}
}
}
if(down==&&right==)//')('
insert(now-((<<bit[j-])<<)-(<<bit[j]),val+a[i][j]);//直接联通即可
if(down==&&right==)//'()'
if(now==((<<bit[j])<<)+(<<bit[j-]))//当前状态只有这两个插头
Ans=max(Ans,val+a[i][j]);//统计答案
}
}
}
}
int main()
{
n=read(),m=read();
for(int i=;i<=;i++) bit[i]=(i<<);
for(int i=;i<=n;i++)
for(int j=;j<=m;j++) a[i][j]=read();
DP();
printf("%lld\n",Ans);
return ;
}

P3190 [HNOI2007]神奇游乐园的更多相关文章

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

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

  2. 洛谷P3190 [HNOI2007]神奇游乐园(插头dp)

    传送门 大概是算第一道自己做出来的插头dp? (虽然都是照着抄板子的) (虽然有个地方死活没调出来最后只能看题解才发现自己错在哪里的) 我就当你们都会插头dp了…… 因为必须得是一条路径,所以扫描线上 ...

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

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

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

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

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

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

  6. 1187: [HNOI2007]神奇游乐园 - BZOJ

    Description 经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一个游乐场,专为旅途中疲惫的人设计. ...

  7. bzoj:1187: [HNOI2007]神奇游乐园

    Description 经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一个游乐场,专为旅途中疲惫的人设计. ...

  8. [bzoj1187][HNOI2007]神奇游乐园

    来自FallDream的博客,未经允许,请勿转载,谢谢, 经历了一段艰辛的旅程后,主人公小P乘坐飞艇返回.在返回的途中,小P发现在漫无边际的沙漠中,有一块狭长的绿地特别显眼.往下仔细一看,才发现这是一 ...

  9. BZOJ1187 [HNOI2007]神奇游乐园(插头dp)

    麻麻我会写插头dp了! 推荐陈丹琦论文:https://wenku.baidu.com/view/3e90d32b453610661ed9f4bd.html 破题调一年 #include <cs ...

随机推荐

  1. Redis实战(十七)Redis各个版本新特性

    序言 Redis1.0 Redis2.0 Redis3.0 Redis4.0 Redis5.0 资料

  2. 通过web传大文件

    上传文件的jsp中的部分 通过form表单向后端发送请求 <form id="postForm" action="${pageContext.request.con ...

  3. 莫队算法 ( MO's algorithm )

    莫队算法是由清华大学神牛莫涛发明的一种处理区间问题的离线算法 算法核心是通过先将问询区间总长度平方分块.然后将所有的问询区间按照左端点所在的块编号排序.在同一块内的则按右端点升序 然后设置左右两个下标 ...

  4. 【Dart学习】-- Dart之消息循环机制[翻译]

    概述 异步任务在Dart中随处可见,例如许多库的方法调用都会返回Future对象来实现异步处理,我们也可以注册Handler来响应一些事件,如:鼠标点击事件,I/O流结束和定时器到期. 这篇文章主要介 ...

  5. WTL拖拽文件

    1.对话框属性中把:Accept Files设置为TRUE,或者ModifyStyleEx(0, WS_EX_ACCEPTFILES); 2.在对话框中添加一个ListBox控件,并关联成员变量:m_ ...

  6. adaptiveThreshold(自适应阈值)

    void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue, int adaptiveMethod, int thr ...

  7. python常用类库总结

    个人学习总结,如有错误,请留言指正. 类库归类总结 类库关系

  8. [51nod1383&1048]整数分解为2的幂:DP

    算法一 分析 \(f[x]=f[x-1]+f[x/2] \times [x \equiv 0 \mod 2],O(n)\) 代码 n=int(input()) f=[0]*(n+5) f[0]=1 m ...

  9. python数据类型之可hash,不可hash

    可变类型的数据不可哈希,如list,字典:同值不同址,不同值同址   列表,字典可变, 数值.字母.字符串.数字.元组不可变:同值同址,不同值不同址 怎么判断可变不可变 ?   总结:改个值 看id是 ...

  10. python正则之match search findall

    match:只匹配一次,开头匹配不上,则不继续匹配 a,b,\w+ match(a,"abcdef") 匹配a >>> re.match("a" ...