BZOJ传送门
洛谷传送门
解析:
还是轮廓线DP裸题,不过有两个细节需要注意一下。
我的写法是从上向下同时从左向右,括号序列转移。每个插头的转移是从左边和上面,以下的叙述就是按照这个转移方式来的。
由于不要求覆盖所有点,只是回路,所以当上方和左方都没有插头的时候,我们可以不强制经过这个点。需要将原状态向下继承。
更新答案的时候,由于是要求只能有一个回路,所以只会在当我们上方和左方的插头是一对匹配的括号,且当前只有这一对括号的时候找到一条新的回路,这时候才能更新答案。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define cs const
cs int INF=0x3f3f3f3f;
struct Map{
static cs int magic=189859;
int key[magic],val[magic];
int sta[magic],top;
Map(){memset(key,-1,sizeof key);memset(val,-INF,sizeof val);}
struct iterator{
Map *belong;
int now;
iterator(Map *a,cs int &_now):belong(a),now(_now){}
int key(){return belong->key[belong->sta[now]];}
int val(){return belong->val[belong->sta[now]];}
iterator operator++(){
++now;
return *this;
}
bool operator!=(cs iterator &b){
return now!=b.now||belong!=b.belong;
}
};
iterator begin(){return iterator(this,1);}
iterator end(){return iterator(this,top+1);}
cs int &operator[](cs int &k)cs{
int h=k%magic;
while((~key[h])&&(key[h]^k))h=(h+1)%magic;
return val[h];
}
int &operator[](cs int &k){
int h=k%magic;
while((~key[h])&&(key[h]^k))h=(h+1)%magic;
if(key[h]^k){
sta[++top]=h;
key[h]=k;
}
return val[h];
}
void clear(){
while(top){
key[sta[top]]=-1;
val[sta[top]]=-INF;
--top;
}
}
}ma[2];
inline void ckmax(int &a,cs int &b){a<b?a=b:0;}
int n,m,pre;
int val[150][150];
int bits[100];
inline int get_state(int s,int j){
return (s&bits[j])>>(j<<1);
}
inline int set_state(int s,int j,int b){
return (s&~bits[j])|(b<<(j<<1));
}
inline int set_state(int s,int j,int bn,int bj){
return (s&~(bits[j]|bits[j+1]))|((bn|(bj<<2))<<(j<<1));
}
inline int find_match(int s,int j){
int c=get_state(s,j),d=c==1?1:-1,f=0;
for(;;j+=d){
if(get_state(s,j)==c)++f;
else if(get_state(s,j))--f;
if(f==0)return j;
}
cout<<"-1";exit(0);
}
int ans=-INF;
inline void dp(){
ma[0].clear(),ma[1].clear();pre=0;
ma[pre][0]=0;
for(int re i=0;i<n;++i)
for(int re j=0;j<m;++j){
int now=pre^1;
ma[now].clear();
for(Map::iterator it=ma[pre].begin();it!=ma[pre].end();++it){
int s=it.key(),nowans=it.val();
if(j==0)s<<=2;
int sl=get_state(s,j),su=get_state(s,j+1);
if(!sl&&!su){
ckmax(ma[now][s],nowans);
if(i+1<n&&j+1<m)ckmax(ma[now][set_state(s,j,1,2)],nowans+val[i][j]);
}
else if(!sl||!su){
if(i+1<n)ckmax(ma[now][set_state(s,j,su|sl,0)],nowans+val[i][j]);
if(j+1<m)ckmax(ma[now][set_state(s,j,0,su|sl)],nowans+val[i][j]);
}
else if(sl==su){
int posl=find_match(s,j),posu=find_match(s,j+1);
int mn=min(posl,posu),mx=max(posl,posu);
int bs=set_state(s,mn,1);
bs=set_state(bs,mx,2);
ckmax(ma[now][set_state(bs,j,0,0)],nowans+val[i][j]);
}
else if(sl==2&&su==1){
ckmax(ma[now][set_state(s,j,0,0)],nowans+val[i][j]);
}
else if(sl==1&&su==2){
if(s==set_state(0,j,sl,su))ckmax(ans,nowans+val[i][j]);
}
}
pre=now;
}
}
signed main(){
scanf("%d%d",&n,&m);
for(int re j=0;j<=m;++j)bits[j]=3<<(j<<1);
for(int re i=0;i<n;++i)
for(int re j=0;j<m;++j){
scanf("%d",&val[i][j]);
}
dp();
cout<<ans<<"\n";
return 0;
}