大概是算第一道自己做出来的插头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写法和很多人不一样诶……)
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<cstring> 5 #define ll long long 6 #define inf 0x3f3f3f3f3f3f3f3f 7 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 8 const int mod=200097; 9 int n,m,c[105][105];ll ans=-0x3f3f3f3f3f3f3f3f; 10 struct Ha{ 11 int key[mod],sz,Hash[mod];ll val[mod]; 12 inline void init(){ 13 memset(val,0xef,sizeof(val)),memset(key,-1,sizeof(key)); 14 sz=0,memset(Hash,0,sizeof(Hash)); 15 } 16 inline void newhash(int id,int state){Hash[id]=++sz,key[sz]=state,val[sz]=-inf;} 17 ll &operator [](const int state){ 18 for(int i=state%mod;;i=(i+1==mod)?0:i+1){ 19 if(!Hash[i]) newhash(i,state); 20 if(key[Hash[i]]==state) return val[Hash[i]]; 21 } 22 } 23 }f[2]; 24 inline int find(int state,int id){return (state>>((id-1)<<1))&3;} 25 inline void set(int &state,int pos,int val){ 26 pos=(pos-1)<<1,state|=3<<pos,state^=3<<pos,state|=val<<pos; 27 } 28 int link(int state,int pos){ 29 int cnt=0,del=(find(state,pos)==1)?1:-1; 30 for(int i=pos;i&&i<=m+1;i+=del){ 31 int plug=find(state,i); 32 if(plug==1) ++cnt; 33 else if(plug==2) --cnt; 34 if(!cnt) return i; 35 } 36 return -1; 37 } 38 void solve(int x,int y){ 39 int now=((x-1)*m+y)&1,last=now^1,tot=f[last].sz; 40 f[now].init(); 41 for(int i=1;i<=tot;++i){ 42 int state=f[last].key[i];ll val=f[last].val[i]; 43 int plug1=find(state,y),plug2=find(state,y+1); 44 if(!plug1&&!plug2){ 45 cmax(f[now][state],val); 46 if(x!=n&&y!=m) set(state,y,1),set(state,y+1,2),cmax(f[now][state],val+c[x][y]); 47 } 48 else if(plug1&&!plug2){ 49 if(x!=n) cmax(f[now][state],val+c[x][y]); 50 if(y!=m) set(state,y,0),set(state,y+1,plug1),cmax(f[now][state],val+c[x][y]); 51 } 52 else if(!plug1&&plug2){ 53 if(y!=m) cmax(f[now][state],val+c[x][y]); 54 if(x!=n) set(state,y,plug2),set(state,y+1,0),cmax(f[now][state],val+c[x][y]); 55 } 56 else if(plug1==1&&plug2==1) 57 set(state,link(state,y+1),1),set(state,y,0),set(state,y+1,0),cmax(f[now][state],val+c[x][y]); 58 else if(plug1==1&&plug2==2){ 59 set(state,y,0),set(state,y+1,0); 60 if(!state) cmax(ans,val+c[x][y]); 61 } 62 else if(plug1==2&&plug2==1) set(state,y,0),set(state,y+1,0),cmax(f[now][state],val+c[x][y]); 63 else if(plug1==2&&plug2==2) 64 set(state,link(state,y),2),set(state,y,0),set(state,y+1,0),cmax(f[now][state],val+c[x][y]); 65 } 66 } 67 int main(){ 68 // freopen("testdata.in","r",stdin); 69 scanf("%d%d",&n,&m); 70 for(int i=1;i<=n;++i) 71 for(int j=1;j<=m;++j) 72 scanf("%d",&c[i][j]); 73 f[0].init(),f[0][0]=0; 74 for(int i=1;i<=n;++i){ 75 for(int j=1;j<=m;++j) solve(i,j); 76 if(i!=n){ 77 int now=(i*m)&1,tot=f[now].sz; 78 for(int j=1;j<=tot;++j) 79 f[now].key[j]<<=2; 80 } 81 } 82 printf("%lld ",ans); 83 return 0; 84 }