ural1519-Formula 1
题意
给出一个 \(n\times m\) 的棋盘,上面有一些格子是不能经过的。求有多少种欧拉回路可以经过所有可经过到格子。\(n,m\le 12\) 。
分析
上个月就看了一下插头dp,然而这道题写不出来。现在来看其实也非常好写,只要把情况讨论清楚,对插头dp理解好就可以了。
我们要求的是欧拉回路,只能有一个环,所以要记录连通性状态,而不仅仅是像 hdu1693 这题一样,只记录轮廓线上是否有插头。
用 \(f(i,j,S)\) 表示转移到 \((i,j)\) 这个格子,轮廓线上方到格子全部被覆盖到,轮廓线状态为 \(S\) 的方案数,考虑如何表示状态 \(S\) 。
观察轮廓线上方的连通性,可以发现,任意两条线都是不相交的,所以插头的匹配情况可以用一个合法的括号序列来表示。因此我们使用三进制表示法,0='',1='(',2=')' 。接下来讨论各种情况。
下面的内容自己画一画图,讨论一下就可以得出了。
将轮廓线从 1 到 \(m+1\) 标号,那么若当前为 \((i,j)\) ,那么此处的下插头标号为 \(j\) ,这个值设为 \(p\) ,右插头标号为 \(j+1\) ,这个值设为 \(q\) 。\((i,j-1)\) 的左插头标号为 \(j\) ,这个值设为 \(x\),上插头标号为 \(j+1\) ,值设为 \(y\) 。
此处是洞,那么只从 \(x=y=0\) 转移到 \(p=q=0\) 。否则:
\(x=y=0\) ,转移到 \(p=1,q=2\) ,新建一个连通分量
\(x=y=1\) ,转移到 \(p=q=0\) ,\(y\) 对应的右括号改为左括号
\(x=y=2\) ,转移到 \(p=q=0\) ,\(x\) 对应的左括号改为右括号
\(x,y\) 中只有一个为 0,转移到 \(p=x+y,q=0\) 或 \(p=0,q=x+y\) ,延续之前到路线或者在此处转弯
\(x=1,y=2\) ,这是对当前的整个连通分量的末端合并,由于我们只能有一条回路,所以这个转移只能在棋盘的最后一个可走位置转移,\(p=q=0\) 。
\(x=2,y=1\) ,合并两个连通分量,\(p=q=0\) 。
讨论就这样啦!
写法上来说,用数组 \(f,g\) 滚动进行dp,用四进制数来存三进制状态,但这样直接开数组会爆炸,而且其中还有很多没有用的状态(不合法的括号序列),所以一开始我们dfs预处理一下状态,并给它们标号,用一个 unordered_map 来存状态到标号的对应。总的状态数上界大概是 \(\frac{\binom {n} {\frac{n}{2}}}{n+1}*2^\frac{n}{2}*(n+1)\) ,大约为 \(1.1\times 10^5\) ,其实是一个比较松的上界。(卡特兰数为合法括号序列个数,删掉其中的某一些对,最后还有一个位置可以放空。其实还应该容斥空的位置,不过这是一个上界而已)。
复杂度为 \(O(nm|S|)\) 。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long giant;
const int maxn=14;
const int maxg=1.2e5;
unordered_map<int,int> id;
int h[maxg],ids=0,a[maxn],mat[maxg][maxn],fx,fy,n,m;
giant f[maxg],g[maxg];
bool ok[maxn][maxn];
inline void match(int mt[]) {
static int sta[maxn];
int top=0;
for (int i=1;i<=m+1;++i) if (a[i]==1) sta[++top]=i; else if (a[i]==2) {
int x=sta[top--];
mt[x]=i;
mt[i]=x;
}
}
inline bool legal() {
int tot=0;
for (int i=1;i<=m+1;++i) if ((tot+=(!a[i]?0:(a[i]==1?1:-1)))<0) return false;
if (tot) return false;
return true;
}
inline int at() {
int ret=0;
for (int i=m+1;i;--i) (ret+=a[i])<<=2;
return ret;
}
void dfs(int now) {
if (now>m+1) {
if (legal()) {
int x=at();
h[id[x]=++ids]=x; // some id is empty!! it equals zero
match(mat[ids]);
}
return;
}
for (int i=0;i<3;++i) a[now]=i,dfs(now+1);
}
inline int get(int x,int p) {
return (x>>(p<<1))&3;
}
inline int mod(int x,int p,int d) {
int tmp=d<<(p<<1),aux=3<<(p<<1);
return (x&(~aux))+tmp;
}
vector<int> dec(int x) {
vector<int> ret;
ret.clear();
for (int i=1;i<=m+1;++i) ret.push_back((x>>(i<<1))&3);
return ret;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
scanf("%d%d",&n,&m);
dfs(1);
for (int i=1;i<=n;++i) {
static char s[maxn];
scanf("%s",s+1);
for (int j=1;j<=m;++j) if (s[j]=='.') {
ok[i][j]=true;
fx=i,fy=j;
}
}
f[id[0]]=1;
for (int i=1;i<=n;++i) {
swap(f,g);
memset(f,0,sizeof f);
for (int j=1;j<=ids;++j) {
int d=h[j];
if (get(d,m+1)==0) f[id[d<<2]]=g[j];
}
for (int j=1;j<=m;++j) {
swap(f,g);
memset(f,0,sizeof f);
for (int k=1;k<=ids;++k) {
int d=h[k],x=get(d,j),y=get(d,j+1);
if (!ok[i][j]) {
if (!x && !y) f[k]+=g[k];
} else {
if (x==0 && y==0) {
int v=mod(mod(d,j,1),j+1,2);
int w=id[v];
f[w]+=g[k];
} else if (x==1 && y==1) {
int v=mod(mod(d,j,0),j+1,0);
v=mod(v,mat[k][j+1],1);
int w=id[v];
f[w]+=g[k];
} else if (x==2 && y==2) {
int v=mod(mod(d,j,0),j+1,0);
v=mod(v,mat[k][j],2);
int w=id[v];
f[w]+=g[k];
} else if (x==0 || y==0) {
int v1=mod(mod(d,j,x+y),j+1,0);
int v2=mod(mod(d,j,0),j+1,x+y);
int w1=id[v1],w2=id[v2];
f[w1]+=g[k],f[w2]+=g[k];
} else if (x==1 && y==2) {
if (i==fx && j==fy) {
int v=mod(mod(d,j,0),j+1,0);
int w=id[v];
f[w]+=g[k];
}
} else if (x==2 && y==1) {
int v=mod(mod(d,j,0),j+1,0);
int w=id[v];
f[w]+=g[k];
}
}
}
}
}
printf("%lld\n",f[id[0]]);
return 0;
}
ural1519-Formula 1的更多相关文章
- URAL1519 Formula 1 —— 插头DP
题目链接:https://vjudge.net/problem/URAL-1519 1519. Formula 1 Time limit: 1.0 secondMemory limit: 64 MB ...
- URAL1519 Formula 1 【插头dp】
题目链接 URAL1519 题解 看题型显然插头\(dp\) 考虑如何设计状态 有这样一个方案 当我们决策到某个位置 轮廓线长这样 你会发现插头一定是相互匹配的 所以我们实际上可以把状态用括号序列表示 ...
- 2019.01.23 ural1519 Formula 1(轮廓线dp)
传送门 轮廓线dpdpdp模板题. 题意简述:给一个放有障碍的网格图,问有多少种方法能使所有非障碍格子都在同一条哈密顿回路上面. 考虑用括号序列的写法来状压这个轮廓线. 用000表示没有插头,111表 ...
- [URAL1519] Formula 1 [插头dp入门]
题面: 传送门 思路: 插头dp基础教程 先理解一下题意:实际上就是要你求这个棋盘中的哈密顿回路个数,障碍不能走 看到这个数据范围,还有回路处理,就想到使用插头dp来做了 观察一下发现,这道题因为都是 ...
- DP设状态 : 状压与线
[NOIP2017]宝藏(状压) [AHOI2009]中国象棋(状压) [BZOJ1814] URAL1519 Formula 1(插头\(DP\)模板) 新链接 : Luogu5056 , dark ...
- HDU1964 Pipes —— 插头DP
题目链接:https://vjudge.net/problem/HDU-1964 Pipes Time Limit: 5000/1000 MS (Java/Others) Memory Limi ...
- FZU1977 Pandora adventure —— 插头DP
题目链接:https://vjudge.net/problem/FZU-1977 Problem 1977 Pandora adventure Accept: 597 Submit: 2199 ...
- URAL1519:Formula 1——题解
http://acm.timus.ru/problem.aspx?space=1&num=1519 https://vjudge.net/problem/URAL-1519 题目大意:给一个网 ...
- redmine computed custom field formula tips
项目中要用到Computed custom field插件,公式不知道怎么写,查了些资料,记录在这里. 1.http://apidock.com/ruby/Time/strftime 查看ruby的字 ...
- salesforce 零基础开发入门学习(十五)salesforce中formula的使用(不含Date/Time)
本文参考官方的formula介绍PDF:https://resources.docs.salesforce.com/200/latest/en-us/sfdc/pdf/salesforce_usefu ...
随机推荐
- 人脸识别引擎SeetaFaceEngine简介及在windows7 vs2013下的编译
SeetaFaceEngine是开源的C++人脸识别引擎,无需第三方库,它是由中科院计算所山世光老师团队研发.它的License是BSD-2. SeetaFaceEngine库包括三个模块:人脸检测( ...
- CF 1064 D. Labyrinth
D. Labyrinth http://codeforces.com/contest/1064/problem/D 题意: n*m的矩阵,只能往左走l次,往右走r次,上下走无限制,问能走到多少个点. ...
- python与其他语言的区别
C 和 Python.Java.C#等 C语言: 代码编译得到 机器码 ,机器码在处理器上直接执行,每一条指令控制CPU工作 其他语言: 代码编译得到 字节码 ,虚拟机执行字节码并转换成机器码再后在处 ...
- dp合集 广场铺砖问题&&硬木地板
dp合集 广场铺砖问题&&硬木地板 很经典了吧... 前排:思想来自yali朱全民dalao的ppt百度文库免费下载 后排:STO朱全民OTZ 广场铺砖问题 有一个 W 行 H 列的广 ...
- VPS挂机赚美刀详细介绍–Alexamaster操作流程
跟 vps 主机打交道时间长了,手里也渐渐积累了些闲置的 vps.让它们这么闲着吧,感觉有些浪费资源:用起来吧,暂时又没有好的项目.一直听说通过 vps挂机可以赚回主机成本,甚至可以盈利.正好这两天有 ...
- Dilworth定理
来自网络的解释: 定理内容及其证明过程数学不好看不懂. 通俗解释: 把一个数列划分成最少的最长不升子序列的数目就等于这个数列的最长上升子序列的长度(LIS) EXAMPLE 1 HDU 1257 ...
- DOM---文档对象模型(Document Object Model)的基本使用
一.DOM简介 文档对象模型(Document Object Model,简称DOM),是W3C组织推荐的处理可扩展置标语言的标准编程接口.它是一种与平台和语言无关的应用程序接口(API),它可以动态 ...
- 如何在Ubuntu 18.04上安装Go
如何在Ubuntu 18.04上安装Go 谢鸢发表于云计算教程系列订阅98 介绍 课程准备 第1步 - 安装Go 第2步 - 设置Go路径 第3步 - 测试您的安装 结论 介绍 Go是Google开发 ...
- 获取label标签内for的属性值-js
<body> <div class="row_2" id="ass"> <label for="aaa"> ...
- loadrunner处理https请求
录制到的脚本如下: login() { lr_think_time(10); web_url("verifycode.jsp", "URL=https://192.168 ...