设f[i][j][s]为轮廓线推到格子(i,j),状态为s的方案数

括号表示一段线的左端和右端,表示成左括号和右括号,状压的时候用1和2表示,0表示已经闭合

下面的蓝线是黄色格子的轮廓线,dp转移要把它转到橙色轮廓线,设已经在状压的s中取到两条边的状态记为b1,b2



然后分很多情况讨论:

(i,j)是障碍:那就只能什么都不放的转移,也就是只能从b1=0,b2=0转移到新轮廓线的b1=0,b2=0

if(!a[i][j])
{
if(!b1&&!b2)
add(x,v);
}

b1=0,b2=0:因为不能空,所以只能转移一个拐角

else if(!b1&&!b2)
{
if(a[i+1][j]&&a[i][j+1])
add(x+b[j-1]+2*b[j],v);
}

b1=0或者b2=0:根据有无障碍判断能不能转移,如果(i,j+1),(i+1,j)都没有障碍的话就有两种转移,以b1=0,b2!=0为例:

一种是接上然后拐弯,这样转移后的轮廓线括号状态不变



另一种是接上直着走,转移后的轮廓线括号状态b1b2互换



b1!=0,b2=0同理

else if(!b1&&b2)
{
if(a[i][j+1])
add(x,v);
if(a[i+1][j])
add(x-b[j]*b2+b[j-1]*b2,v);
}
else if(b1&&!b2)
{
if(a[i][j+1])
add(x-b[j-1]*b1+b[j]*b1,v);
if(a[i+1][j])
add(x,v);
}

b1=b2=1或2:这样这两条线会在(i,j)格子连起来,两队括号合成一对,以b1=b2=1为例:

else if(b1==1&&b2==1)
{
for(int t=1,l=j+1;l<=m;l++)
{
if((x>>(l*2))%4==1)
t++;
if((x>>(l*2))%4==2)
t--;
if(!t)
{
add(x-b[j]-b[j-1]-b[l],v);
break;
}
}
}
else if(b1==2&&b2==2)
{
for(int t=1,l=j-2;l>=0;l--)
{
if((x>>(l*2))%4==1)
t--;
if((x>>(l*2))%4==2)
t++;
if(!t)
{
add(x+b[l]-2*b[j]-2*b[j-1],v);
break;
}
}
}

b1=2,b2=1:和上面差不多,就是把这两个括号合并就行了

else if(b1==2&&b2==1)
add(x-2*b[j-1]-b[j],v);

b1=1,b2=2:这个只有到最后一个没障碍的点才能转移,因为这是把一条线连成一个回路的最后一步

其实不用转移,直接加进答案就行了

else if(i==tx&&j==ty)
ans+=v;
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=15,mod=299989;
int n,m,la,nw,a[N][N],b[N],c[2],h[300005],tx,ty;
long long ans;
char s[N];
struct qwe
{
int ne,to[2];
long long va[2];
}e[300005];
void add(int x,long long v)
{
int u=x%mod+1;
for(int i=h[u];i;i=e[i].ne)
if(e[i].to[nw]==x)
{
e[i].va[nw]+=v;
return;
}
e[++c[nw]].ne=h[u];
e[c[nw]].to[nw]=x;
e[c[nw]].va[nw]=v;
h[u]=c[nw];
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s",s+1);
for(int j=1;j<=m;j++)
if(s[j]=='.')
a[i][j]=1,tx=i,ty=j;
}
b[0]=1;
for(int i=1;i<=12;i++)
b[i]=b[i-1]<<2;
c[0]=1,e[1].va[0]=1,e[1].to[0]=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=c[nw];j++)
e[j].to[nw]<<=2;
for(int j=1;j<=m;j++)
{
la=nw,nw^=1;
memset(h,0,sizeof(h));
c[nw]=0;
for(int k=1;k<=c[la];k++)
{
int x=e[k].to[la],b1=(x>>(j*2-2))%4,b2=(x>>(j*2))%4;
long long v=e[k].va[la];
if(!a[i][j])
{
if(!b1&&!b2)
add(x,v);
}
else if(!b1&&!b2)
{
if(a[i+1][j]&&a[i][j+1])
add(x+b[j-1]+2*b[j],v);
}
else if(!b1&&b2)
{
if(a[i][j+1])
add(x,v);
if(a[i+1][j])
add(x-b[j]*b2+b[j-1]*b2,v);
}
else if(b1&&!b2)
{
if(a[i][j+1])
add(x-b[j-1]*b1+b[j]*b1,v);
if(a[i+1][j])
add(x,v);
}
else if(b1==1&&b2==1)
{
for(int t=1,l=j+1;l<=m;l++)
{
if((x>>(l*2))%4==1)
t++;
if((x>>(l*2))%4==2)
t--;
if(!t)
{
add(x-b[j]-b[j-1]-b[l],v);
break;
}
}
}
else if(b1==2&&b2==2)
{
for(int t=1,l=j-2;l>=0;l--)
{
if((x>>(l*2))%4==1)
t--;
if((x>>(l*2))%4==2)
t++;
if(!t)
{
add(x+b[l]-2*b[j]-2*b[j-1],v);
break;
}
}
}
else if(b1==2&&b2==1)
add(x-2*b[j-1]-b[j],v);
else if(i==tx&&j==ty)
ans+=v;
}
}
}
printf("%lld\n",ans);
return 0;
}

bzoj 1814: Ural 1519 Formula 1【插头dp】的更多相关文章

  1. bzoj 1814 Ural 1519 Formula 1 插头DP

    1814: Ural 1519 Formula 1 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 942  Solved: 356[Submit][Sta ...

  2. bzoj 1814 Ural 1519 Formula 1 ——插头DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1814 普通的插头 DP .但是调了很久.注意如果合并两个 1 的话,不是 “把向右第一个 2 ...

  3. bzoj 1814: Ural 1519 Formula 1 插头dp经典题

    用的括号序列,听说比较快. 然并不会预处理,只会每回暴力找匹配的括号. #include<iostream> #include<cstdio> #include<cstr ...

  4. bzoj1814 Ural 1519 Formula 1(插头dp模板题)

    1814: Ural 1519 Formula 1 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 924  Solved: 351[Submit][Sta ...

  5. 【BZOJ1814】Ural 1519 Formula 1 插头DP

    [BZOJ1814]Ural 1519 Formula 1 题意:一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数.(n,m<=12) 题解:插头DP板子题,刷板 ...

  6. Ural 1519 Formula 1 插头DP

    这是一道经典的插头DP单回路模板题. 用最小表示法来记录连通性,由于二进制的速度,考虑使用8进制. 1.当同时存在左.上插头的时候,需要判断两插头所在连通块是否相同,若相同,只能在最后一个非障碍点相连 ...

  7. BZOJ1814: Ural 1519 Formula 1(插头Dp)

    Description Regardless of the fact, that Vologda could not get rights to hold the Winter Olympic gam ...

  8. 【Ural】1519. Formula 1 插头DP

    [题目]1519. Formula 1 [题意]给定n*m个方格图,有一些障碍格,求非障碍格的哈密顿回路数量.n,m<=12. [算法]插头DP [题解]<基于连通性状态压缩的动态规划问题 ...

  9. 【BZOJ1814】Ural 1519 Formula 1 (插头dp)

    [BZOJ1814]Ural 1519 Formula 1 (插头dp) 题面 BZOJ Vjudge 题解 戳这里 上面那个链接里面写的非常好啦. 然后说几个点吧. 首先是关于为什么只需要考虑三进制 ...

随机推荐

  1. vue - 前置工作 - 安装vsCode以及插件

    开发环境:Win7 x64 开发工具:vsCOde 开发工具vsCode插件配置:Vetur.ivue.Vue 2 Snippets Vetur:强力推荐的一款插件,为什么呢? 格式化代码.高亮.代码 ...

  2. vimrc 避免中文乱码配置

    et smsyntax onset ts=4set sts=4set sw=4set hlsearchset rulerset backspace=indent,eol,startset encodi ...

  3. 【转载】.NET Remoting学习笔记(三)信道

    目录 .NET Remoting学习笔记(一)概念 .NET Remoting学习笔记(二)激活方式 .NET Remoting学习笔记(三)信道 参考:♂风车车.Net .NET Framework ...

  4. 如何理解pca和svd的关系?

    主成分分析和奇异值分解进行降维有何共同点? 矩阵的奇异值分解 当矩阵不是方阵,无法为其定义特征值与特征向量,可以用一个相似的概念来代替:奇异值. 通常用一种叫奇异值分解的算法来求取任意矩阵的奇异值: ...

  5. busybox 终端支持 ctrl-r

    Busybox Settings ---> Busybox Library Tuning ---> [*] History saving [ ] Save history on shell ...

  6. MySQL基本语句优化10个原则

    在数据库应用中,程序员们通过不断的实践总结了很多经验,这些经验是一些普遍适用的规则.每一个程序员都应该了解并记住它们,在构造SQL语句时,养成良好的习惯.以下10条比较重要的原则供大家参考. 原则1: ...

  7. Linux搭建lnmp环境

    在CentOS 6上使用yum安装lnmp服务,原文链接http://www.qiansw.com/yum-lnmp.html

  8. 微信小程序 新手入门教程

    因为工作需要,最近学习了一下微信小程序,在此分享一下大概的流程. 强烈建议大家先去看微信小程序简易教程:点我进入 起步: 安装微信web开发软件者工具,需要破解的同学可以网上找破解教程,很简单的,这里 ...

  9. mysql优化-----多列索引的左前缀规则

    索引优化策略 :索引类型 .1B-tree索引 关注的是:Btree索引的左前缀匹配规则,索引在排序和分组上发挥的作用. 注:名叫btree索引,大的方面看都用的二叉树.平衡树.但具体的实现上,各引擎 ...

  10. LIS n^2&nlogn模板

    LIS nlogn模板 http://acm.hdu.edu.cn/showproblem.php?pid=1950 #include <iostream> #include <st ...