bzoj 1814 Ural 1519 Formula 1 ——插头DP
题目: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的更多相关文章
- 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 ...
- bzoj 1814: Ural 1519 Formula 1 插头dp经典题
用的括号序列,听说比较快. 然并不会预处理,只会每回暴力找匹配的括号. #include<iostream> #include<cstdio> #include<cstr ...
- bzoj1814 Ural 1519 Formula 1(插头dp模板题)
1814: Ural 1519 Formula 1 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 924 Solved: 351[Submit][Sta ...
- 【BZOJ1814】Ural 1519 Formula 1 插头DP
[BZOJ1814]Ural 1519 Formula 1 题意:一个 m * n 的棋盘,有的格子存在障碍,求经过所有非障碍格子的哈密顿回路个数.(n,m<=12) 题解:插头DP板子题,刷板 ...
- Ural 1519 Formula 1 插头DP
这是一道经典的插头DP单回路模板题. 用最小表示法来记录连通性,由于二进制的速度,考虑使用8进制. 1.当同时存在左.上插头的时候,需要判断两插头所在连通块是否相同,若相同,只能在最后一个非障碍点相连 ...
- bzoj 1814: Ural 1519 Formula 1【插头dp】
设f[i][j][s]为轮廓线推到格子(i,j),状态为s的方案数 括号表示一段线的左端和右端,表示成左括号和右括号,状压的时候用1和2表示,0表示已经闭合 下面的蓝线是黄色格子的轮廓线,dp转移要把 ...
- BZOJ1814: Ural 1519 Formula 1(插头Dp)
Description Regardless of the fact, that Vologda could not get rights to hold the Winter Olympic gam ...
- 【Ural】1519. Formula 1 插头DP
[题目]1519. Formula 1 [题意]给定n*m个方格图,有一些障碍格,求非障碍格的哈密顿回路数量.n,m<=12. [算法]插头DP [题解]<基于连通性状态压缩的动态规划问题 ...
- 【BZOJ1814】Ural 1519 Formula 1 (插头dp)
[BZOJ1814]Ural 1519 Formula 1 (插头dp) 题面 BZOJ Vjudge 题解 戳这里 上面那个链接里面写的非常好啦. 然后说几个点吧. 首先是关于为什么只需要考虑三进制 ...
随机推荐
- 在Altium Designer 10中实现元器件旋转45°角放置
Tool--->Preferences >> PCB Editor >> General 将Rotation Step(旋转的步进值)由90改为45,这样以后每次按空格键 ...
- 【sparkSQL】SparkSession的认识
https://www.cnblogs.com/zzhangyuhang/p/9039695.html https://www.jianshu.com/p/dea6a78b9dff 在Spark1.6 ...
- Sql server数据库连接Oracle库的步骤
本地使用环境 操作系统: win10 64 ,SQL Server 2012 ,Oracle Server 11g 第一步:安装好oracle客户端,并配置好TNS信息 ORCL = (DESCR ...
- 移动web技能总结
对于作为一名前端开发人员,除了能够编写出满足需求的PC端页面之外,同时也是需要懂得怎么去制作移动web页面,毕竟使用移动设备来操作任何处理称为新时代的趋势,所以学好制作一个移动web时必须滴.于是通过 ...
- java九九乘法表
public class Nine { public static void main(String[] args) { //外层循环控制行数 for (int i = 9;i >=1;i--) ...
- spoj mgame
题解: f[i][j]表示先后手最大差 g[i][j]表示在最大差的时候是否有后手没得走 代码: #include<bits/stdc++.h> using namespace std; ...
- python ----元组方法以及修改细节
元组的一级元素不可修改 #元组,有序 tu = (111,"alex",(11,22),[(33,44)],True,33,44,) v = tu[3][0][0] print(v ...
- 下载EU台网(欧洲台网)的地震波数据
retrievedata.py ### here first to check the existence of the focal mechanism event file in the NDK d ...
- 2/18 (pycharm 快捷键、循环、join语句)
Alt + Enter 快速修正 Ctrl + / 行注释/取消行注释 Ctrl + Shift + / 块注释 Ctrl + Alt + I 自动缩进 CTRL + D 复制选定的区域或 ...
- ES6 用Promise对象实现的 Ajax 操作
下面是一个用Promise对象实现的 Ajax 操作的例子. const getJSON = function(url) { const promise = new Promise(function( ...