(供复习使用)
插头,其实就是一条线的端点
特别的,左边对应左插头,右边对应右插头
插头DP其实就是一类状压
\(1\) 代表该位置为左插头
\(2\) 代表为右插头
\(0\) 表示无插头
图就不画了,很多题解都画得很好,
这里只解释一下转移
(此时枚举的状态为 zt 方案数为 val b1 为台阶的侧边 b2 为台阶的上端)
if(!mp[i][j]) { if(!b1&&!b2) { ins(zt,val); } }
如果该点不能放点,左上为零才合法
if(!b1&&!b2) { if(mp[i+1][j]&&mp[i][j+1]) { ins(zt+bin[j-1]+2*bin[j],val); } }
如果左上为零,那只有联通右下才合法
f(!b1&&b2) {
if(mp[i][j+1]) ins(zt,val);
if(mp[i+1][j]) ins(zt+b2*bin[j-1]-b2*bin[j],val);
}
if(b1&&!b2) {
if(mp[i][j+1]) ins(zt+b1*bin[j]-b1*bin[j-1],val);
if(mp[i+1][j]) ins(zt,val);
}
如果只有左零或上零,考虑另一端端的连接方向即可
if(b1==1&&b2==1) {
int kl=1;
for(re int t=j+1;t<=m;t++) {
if((zt>>(t*2))%4==1) kl++;
if((zt>>(t*2))%4==2) kl--;
if(!kl) { ins(zt-bin[j]-bin[j-1]-bin[t],val); break; }
}
}
if(b1==2&&b2==2) {
int kl=1;
for(re int t=j-2;t>=0;t--) {
if((zt>>(t*2))%4==1) kl--;
if((zt>>(t*2))%4==2) kl++;
if(!kl) { ins(zt-2*bin[j]-2*bin[j-1]+bin[t],val); break; }
}
}
如果左上相等,连接变值即可
if(b1==2&&b2==1) ins(zt-2*bin[j-1]-bin[j],val);
if(i==e1&&j==e2) ans+=val;
两种连值,其中 \(e1\) 和 \(e2\) 为最后枚举到的可放点