题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1814

普通的插头 DP 。但是调了很久。注意如果合并两个 1 的话,不是 “把向右第一个 2 该成 1 ”,而是 “把向右第一个没有与 1 匹配的 2 改成 1 ”。

原来获取哈希值是用字符串哈希的方法,遍历12个位置;太慢。直接对某数取模作为哈希值,手写哈希表保证不会找错状态。大概 1e5 个状态?

在转移的时候看一下下方和右边有没有障碍、只做合法的转移的话,取答案的时候就不用在判断 “当前两个位置是 1 和 2 ”之外再判断 “其余位置都是 0 ” 了。

自己写的是 “如果当前位置是结束位置且当前两个插口是 1 和 2 就输出答案并 break ” 。这样无解的时候要手动输出 0 。

滚动数组。并且只遍历有效的状态。方法是用手写队列存 “得到转移” 的状态,用 vis 判断该状态是否已经在队列里;把下一层的队列做好之后,遍历下一层(不是这一层)的队列把 vis 清空即可。

注意 long long 。

哈希表的映射方式是:原状态 -> 哈希值 -> ++tot 地分配空间 -> 原状态 。“ -> ” 就是要记下的对应关系。因为哈希值要用数组记它对应哪个位置,所以哈希值不宜太大。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=,M=1e5+;//mention
int n,m,bin[N],q[][M],t[]; ll dp[][M];
bool b[N][N],vis[M],en[N][N];
namespace H{
const int md=1e6+;//
int hd[md+],xnt,nxt[M],vl[M];
int Ps(int s)
{
int h=s%md;
for(int i=hd[h];i;i=nxt[i])
if(vl[i]==s){return i;}
vl[++xnt]=s; nxt[xnt]=hd[h]; hd[h]=xnt;
return xnt;
}
}
int get(int cr,int j){ return (cr&(bin[j+]-bin[j]))>>(*j);}
void cz(int d,bool v){ if(!vis[d]) vis[d]=,q[v][++t[v]]=d;}
void solve()
{
bin[]=; int lm=m+;
for(int i=;i<=lm;i++)bin[i]=bin[i-]<<;
bool flag=;
for(int i=n;i&&!flag;i--)
for(int j=m;j;j--)
if(!b[i][j]){en[i][j]=flag=;break;}
bool u=,v=; flag=;
dp[u][H::Ps()]=; q[u][++t[u]]=;
for(int i=;i<=n;i++)
{
for(int j=;j<=m;j++)
{
for(int c=;c<=t[u];c++)
{
int cr=H::vl[q[u][c]];ll tp=dp[u][q[u][c]];//ll!!!
int d0=get(cr,j-), d1=get(cr,j), t0,t1;
if(b[i][j])
{
if(!d0&&!d1)
{ t0=H::Ps(cr); cz(t0,v); dp[v][t0]+=tp;}
continue;
}
if(en[i][j])
{
if(d0==&&d1==)
{ printf("%lld\n",tp);flag=;break;}
continue;
}
if((!d0&&d1)||(!d1&&d0))
{
t0=cr; t1=cr+d1*bin[j-]-d0*bin[j-]+d0*bin[j]-d1*bin[j];
if(i<n&&!b[i+][j])
{if(d0){t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp;}
else{t1=H::Ps(t1); cz(t1,v); dp[v][t1]+=tp;}}
if(j<m&&!b[i][j+])
{if(d0){t1=H::Ps(t1); cz(t1,v); dp[v][t1]+=tp;}
else{t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp;}}
continue;
}
if(!d0&&!d1&&i<n&&j<m&&!b[i+][j]&&!b[i][j+])
{
t0=cr+bin[j-]+*bin[j];
t0=H::Ps(t0); cz(t0,v);
dp[v][t0]+=tp; continue;
}
if(d0==&&d1==)
{
t0=cr-bin[j-]-bin[j];
for(int p=j+,top=,d;p<=m;p++)
{
d=get(t0,p);
if(d==)top++; else if(d==&&top)top--;
else if(d==){t0-=bin[p];break;}
}
t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp; continue;
}
if(d0==&&d1==)
{
t0=cr-*bin[j-]-*bin[j];//2*!!!
for(int p=j-,top=,d;p>=;p--)
{
d=get(t0,p);
if(d==)top++; else if(d==&&top)top--;
else if(d==){t0+=bin[p];break;}
}
t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp;
continue;
}
if(d0==&&d1==)
{
t0=cr-*bin[j-]-bin[j];
t0=H::Ps(t0); cz(t0,v); dp[v][t0]+=tp; continue;
}
}
if(flag)break;
for(int c=;c<=t[u];c++)dp[u][q[u][c]]=;
for(int c=;c<=t[v];c++)vis[q[v][c]]=;//v not u!!!
t[u]=; swap(u,v);
}
if(flag)break;
for(int c=;c<=t[u];c++)
{
int cr=H::vl[q[u][c]];ll tp=dp[u][q[u][c]];//ll!!!
if(get(cr,m))continue;
int d=cr<<;
d=H::Ps(d); cz(d,v); dp[v][d]=tp;
}
for(int c=;c<=t[u];c++)dp[u][q[u][c]]=;
for(int c=;c<=t[v];c++)vis[q[v][c]]=;
t[u]=; swap(u,v);
}
if(!flag)puts("");///
}
int main()
{
scanf("%d%d",&n,&m); char ch[N];
for(int i=;i<=n;i++)
{
scanf("%s",ch+);
for(int j=;j<=m;j++)
b[i][j]=(ch[j]=='*');
}
solve();
return ;
}

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经典题

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

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

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

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

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

  5. Ural 1519 Formula 1 插头DP

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

  6. bzoj 1814: Ural 1519 Formula 1【插头dp】

    设f[i][j][s]为轮廓线推到格子(i,j),状态为s的方案数 括号表示一段线的左端和右端,表示成左括号和右括号,状压的时候用1和2表示,0表示已经闭合 下面的蓝线是黄色格子的轮廓线,dp转移要把 ...

  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. Python自学:第三章 在列表末尾添加元素与在列表中插入元素

    motorcycles = ['honda', 'yamaha' ,'suzuki'] motorcycles.insert(0, "ducati") print(motorcyc ...

  2. Mysql5.7出现this is incompatible with sql_mode=only_full_group_by

    vi /etc/my.cnf #编辑mysql配置文件 在 [mysqld]和[mysql]下添加 sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZE ...

  3. SASS 简单实用

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. UTC,BJT时间的换算

    题目内容:UTC是世界协调时,BJT是北京时间,UTC时间相当于BJT减去8.现在,你的程序要读入一个整数,表示BJT的时和分.整数的个位和十位表示分,百位和千位表示小时.如果小时小于10,则没有千位 ...

  5. Python—字符串的操作

    字符串的操作 变量: 变量只能是 字母,数字或下划线的任意组合,但首个字符不能为数字,且不能有空格 以下关键字不能声明为变量: and ,as, assert, break ,class ,conti ...

  6. python-模块2

    from collections import namedtuple # # 类 # p = namedtuple("Point", ["x", "y ...

  7. adb command not found / abd' 不是内部或外部命令,也不是可运行的程序 或批处理文件。最简易修改

    此处提供最简易高效的方法 不需要添加.bash_profile 只需手动设置环境变量 1.打开环境变量设置页面:确保你ANDROID_HOME, JAVA_HOME已经设置好,我们针对abd的环境配置 ...

  8. JavaScript HTML DOM - 改变 CSS

    HTML DOM 允许 JavaScript 改变 HTML 元素的样式. 改变 HTML 样式 如需改变 HTML 元素的样式,请使用这个语法: document.getElementById(id ...

  9. tensorFlow(一)相关重要函数理解

    1.函数及参数:tf.nn.conv2d conv2d( input, filter, strides, padding, use_cudnn_on_gpu=True, data_format='NH ...

  10. 指导手册03:Hadoop基础操作

    指导手册03:Hadoop基础操作 Part 1:查看Hadoop集群的基本信息1.查询存储系统信息(1)在WEB浏览器的地址栏输入http://master:50070/ 请查看自己的Hadoop集 ...