题目链接

URAL1519

题解

看题型显然插头\(dp\)

考虑如何设计状态



有这样一个方案

当我们决策到某个位置

轮廓线长这样



你会发现插头一定是相互匹配的

所以我们实际上可以把状态用括号序列表示

如上图就是(#)()

是一个三进制数

那么我们设\(f[i][j][s]\)表示决策到\((i,j)\),轮廓线状态为\(s\)的方案数

我们同时记\(0\)为空插头,\(1\)为表示左括号的插头,\(2\)为表示有括号的插头

先不管空间问题,我们考虑一下转移

有比较多的情况

我们记\(b1\),\(b2\)为\((i,j)\)的左、上插头

\(b1 = 0,b2 = 0\)

首先如果\((i,j)\)本身是障碍格,那么它右插头和下插头也为\(0\)

否则如果对应方向没有障碍,\((i,j)\)右下插头为\(12\)

\(b1\)和\(b2\)有一者为\(0\),那么转移的时候另一个括号的位置放哪里都可以,只需要判断有无障碍

\(b1\)和\(b2\)为同一种括号,我们只需往另一侧查找匹配的括号,改变方向

例如((#))变为###()

如图所示:



把左边两个连起来,右边两个插头就变成了匹配的括号

即由((#))变为###()

\(b1 = 2\)且\(b2 = 1\)

就是(#)(#)这种情况,可以变为(####)

\(b1 = 1\)且\(b2 = 2\)

除非是最后一个格子,否则不能贸然连起来,不然就会出现不连通的情况

具体实现的时候,可以使用四进制而结合位运算加快速度

由于空间比较小,我们需要滚动数组,并且使用\(hash\)表储存状态

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
#include<vector>
#define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define mp(a,b) make_pair<int,int>(a,b)
#define cls(s) memset(s,0,sizeof(s))
#define cp pair<int,int>
#define LL long long int
using namespace std;
const int maxn = 13,maxm = 5000000,INF = 1000000000,P = 201611;
inline int read(){
int out = 0,flag = 1; char c = getchar();
while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
return out * flag;
}
int n,m,sx,sy;
char S[maxn][maxn];
int now,tot[2],h[2][P],nxt[2][maxm],num[2][maxm];
LL f[2][maxm],ans;
inline void add(int s,LL x){
int tmp = s % P;
for (int k = h[now][tmp]; k; k = nxt[now][k])
if (num[now][k] == s){f[now][k] += x; return;}
nxt[now][++tot[now]] = h[now][tmp]; h[now][tmp] = tot[now];
num[now][tot[now]] = s; f[now][tot[now]] = x;
}
inline bool isok(int x,int y){
return x >= 1 && x <= n && y >= 1 && y <= m && S[x][y] != '*';
}
void work(){
int las = 1,e,s,b1,b2;
LL x;
f[0][1] = tot[0] = 1; num[0][1] = 0;
for (int i = 1; i <= n; i++){
for (int k = 1; k <= tot[now]; k++) num[now][k] <<= 2;
for (int j = 1; j <= m; j++){
now ^= 1; las ^= 1;
cls(h[now]); tot[now] = 0;
for (int k = 1; k <= tot[las]; k++){
s = num[las][k]; x = f[las][k];
b1 = (s >> (j - 1 << 1)) & 3;
b2 = (s >> (j << 1)) & 3;
e = s ^ (b1 << (j - 1 << 1)) ^ (b2 << (j << 1));
if (b1 == 0 && b2 == 0){
if (S[i][j] == '*') add(e,x);
else if (isok(i + 1,j) && isok(i,j + 1))
add(e | (1 << (j - 1 << 1)) | (2 << (j << 1)),x);
}
else if (b1 == 0){
if (isok(i,j + 1)) add(s,x);
if (isok(i + 1,j)) add(e | (b2 << (j - 1 << 1)),x);
}
else if (b2 == 0){
if (isok(i + 1,j)) add(s,x);
if (isok(i,j + 1)) add(e | (b1 << (j << 1)),x);
}
else if (b1 == 1 && b2 == 1){
int cnt = 1;
for (int p = j + 1; p <= m + 1; p++){
if ((e >> (p << 1) & 3) == 1) cnt++;
if ((e >> (p << 1) & 3) == 2) cnt--;
if (!cnt){add(e ^ (3 << (p << 1)),x); break;}
}
}
else if (b1 == 2 && b2 == 2){
int cnt = 1;
for (int p = j - 2; ~p; p--){
if ((e >> (p << 1) & 3) == 2) cnt++;
if ((e >> (p << 1) & 3) == 1) cnt--;
if (!cnt){add(e ^ (3 << (p << 1)),x); break;}
}
}
else if (b1 == 2 && b2 == 1) add(e,x);
else if (i == sx && j == sy) ans += x;
}
}
}
printf("%lld\n",ans);
}
int main(){
n = read(); m = read();
REP(i,n) scanf("%s",S[i] + 1);
REP(i,n) REP(j,m) if (S[i][j] == '.') sx = i,sy = j;
work();
return 0;
}

URAL1519 Formula 1 【插头dp】的更多相关文章

  1. URAL1519 Formula 1 —— 插头DP

    题目链接:https://vjudge.net/problem/URAL-1519 1519. Formula 1 Time limit: 1.0 secondMemory limit: 64 MB ...

  2. [URAL1519] Formula 1 [插头dp入门]

    题面: 传送门 思路: 插头dp基础教程 先理解一下题意:实际上就是要你求这个棋盘中的哈密顿回路个数,障碍不能走 看到这个数据范围,还有回路处理,就想到使用插头dp来做了 观察一下发现,这道题因为都是 ...

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

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

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

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

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

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

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

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

  7. Ural 1519 Formula 1 插头DP

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

  8. URAL Formula 1 ——插头DP

    [题目分析] 一直听说这是插头DP入门题目. 难到爆炸. 写了2h,各种大常数,ural垫底. [代码] #include <cstdio> #include <cstring> ...

  9. 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 ...

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

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

随机推荐

  1. JavaWeb(十七)——JSP中的九个内置对象

    一.JSP运行原理 每个JSP 页面在第一次被访问时,WEB容器都会把请求交给JSP引擎(即一个Java程序)去处理.JSP引擎先将JSP翻译成一个_jspServlet(实质上也是一个servlet ...

  2. PHP:Iterator(迭代器)接口和生成器

    迭代器 可在内部迭代自己的外部迭代器或类的接口.详情:http://php.net/manual/zh/class.iterator.php 接口摘要 Iterator extends Travers ...

  3. mac安装pkg 一直“正在验证” 卡着

    今天换了新mac, 但是之前wireshark(抓包工具) 不能用了 ,要安装Xquartz. 下载之后一直卡着, 网上找了半天没有解决方法. 最后我重启一下就好了... 重启一下. 2. 15款ma ...

  4. Hbase 教程-安装

    HBase安装 安装前设置 安装Hadoop在Linux环境下之前,需要建立和使用Linux SSH(安全Shell).按照下面设立Linux环境提供的步骤. 创建一个用户 首先,建议从Unix创建一 ...

  5. PHP性能优化 -理论篇

    什么情况下,遇到了PHP性能问题?    1 PHP语法使用的不恰当    2 使用PHP语言做不了它不擅长做的事    3 用php语言连接的服务不给力    4 PHP自身的短板    5 我也不 ...

  6. Java实现在线预览功能

    java实现在线预览功能,需要用到  jacob.dll jacob.jar   预览pdf所需js  pdfobject.min.js 将上传文件转为pdf保存. <div class=&qu ...

  7. Scrum立会报告+燃尽图(十月十三日总第四次):前期宣传相关工作

    此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2194 Scrum立会master:刘欣 一.小组介绍 组长:付佳 组员: ...

  8. 基础系列(6)—— C#类和对象

    一.类介绍       类(class)是C#类型中最基础的类型.类是一个数据结构,将状态(字段)和行为(方法和其他函数成员)组合在一个单元中.类提供了用于动态创建类实例的定义,也就是对象(objec ...

  9. FPGA论文

    基于 NetFPGA 的 VCP 网络的设计与实现 --可变结构拥塞控制协议(VCP),适应于高带宽时延乘积网络的显式拥塞控制协议 无源光网络(PON) 1.区块链技术发展,物联网设备激增,服务器压力 ...

  10. Throwable、Error、Exception、RuntimeException 区别 联系

    1.Throwable 类是 Java 语言中所有错误或异常的超类.它的两个子类是Error和Exception: 2.Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获 ...