【BZOJ 4572】【SCOI 2016】围棋
http://www.lydsy.com/JudgeOnline/problem.php?id=4572
轮廓线DP:设\(f(i,j,S,x,y)\)。
\(S\)表示\((i,1)\)到\((i,j)\)和\((i-1,j+1)\)到\((i-1,m)\)的长度为m的轮廓线上与每个位置作为末位是否与第一个串匹配的状态。
\(x,y\)分别表示\((i,j)\)这个位置作为末位与第一/二个串kmp到了哪个位置。
\(x,y\)取值范围是\([0,c)\),因为当\(x,y\)其一取到c时,这个状态主要考虑对下一个位置上状态的贡献,所以会沿着失配指针往前跳一个继续匹配,不如把\(x/y=c\)的状态和\(x/y=fail[c]\)的状态压在一起。
注意有的连通性状压轮廓线长度为m+1,这个不关心8联通,所以长度为m。
又因为\(S\)的前\(c-1\)位一定是0,可以不记录这几位,所以S的长度是\(m-c+1\)。
时间复杂度\(O(nm2^{m-c+1}c^2)\)。
注意滚动数组一定要全部清空!
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mo = 1000000007;
int n, m, c, q, r1[10], r2[10], fail1[10], fail2[10];
int f[1 << 12][6][6], g[1 << 12][6][6], t1[10][10], t2[10][10];
char c1[10], c2[10];
int change(int S, int tmp, int mark) {
if (tmp < 0) return S;
return S ^ ((mark ^ ((S >> tmp) & 1)) << tmp);
}
int ipow(int a, int b) {
int ret = 1, w = a;
while (b) {
if (b & 1) ret = 1ll * ret * w % mo;
w = 1ll * w * w % mo;
b >>= 1;
}
return ret;
}
int main() {
scanf("%d%d%d%d", &n, &m, &c, &q);
int ans_tot = ipow(3, n * m);
while (q--) {
scanf("%s%s", c1 + 1, c2 + 1);
for (int i = 1; i <= c; ++i) {if (c1[i] == 'W') r1[i] = 1; if (c1[i] == 'B') r1[i] = 2; if (c1[i] == 'X') r1[i] = 0;}
for (int i = 1; i <= c; ++i) {if (c2[i] == 'W') r2[i] = 1; if (c2[i] == 'B') r2[i] = 2; if (c2[i] == 'X') r2[i] = 0;}
int p = 0;
for (int i = 2; i <= c; ++i) {
while (p && r1[p + 1] != r1[i]) p = fail1[p];
fail1[i] = r1[p + 1] == r1[i] ? ++p : 0;
}
p = 0;
for (int i = 2; i <= c; ++i) {
while (p && r2[p + 1] != r2[i]) p = fail2[p];
fail2[i] = r2[p + 1] == r2[i] ? ++p : 0;
}
for (int i = 0; i < c; ++i)
for (int j = 0; j <= 2; ++j) {
p = i; while (p && r1[p + 1] != j) p = fail1[p];
t1[i][j] = r1[p + 1] == j ? p + 1 : 0;
p = i; while (p && r2[p + 1] != j) p = fail2[p];
t2[i][j] = r2[p + 1] == j ? p + 1 : 0;
}
memset(f, 0, sizeof(f));
memset(g, 0, sizeof(g));
g[0][0][0] = 1;
int bas = (1 << (m - c + 1)) - 1, newx, newy, T;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= m; ++j) {
if (j != 1) memcpy(f, g, sizeof(f));
else {
memset(f, 0, sizeof(f));
for (int S = 0; S <= bas; ++S)
for (int x = 0; x < c; ++x)
for (int y = 0; y < c; ++y)
if (g[S][x][y])
(f[S][0][0] += g[S][x][y]) %= mo;
}
memset(g, 0, sizeof(g));
for (int S = 0; S <= bas; ++S)
for (int x = 0; x < c; ++x)
for (int y = 0; y < c; ++y)
if (f[S][x][y])
for (int now = 0; now <= 2; ++now) {
newx = t1[x][now]; newy = t2[y][now];
if (newy == c && j - c >= 0 && ((S >> (j - c)) & 1)) continue;
if (newx == c) T = change(S, j - c, 1);
else T = change(S, j - c, 0);
if (newx == c) newx = fail1[c];
if (newy == c) newy = fail2[c];
(g[T][newx][newy] += f[S][x][y]) %= mo;
}
}
}
int ans = ans_tot;
for (int S = 0; S <= bas; ++S)
for (int x = 0; x < c; ++x)
for (int y = 0; y < c; ++y)
((ans -= g[S][x][y]) += mo) %= mo;
printf("%d\n", ans);
}
}
【BZOJ 4572】【SCOI 2016】围棋的更多相关文章
- bzoj 4568 [SCOI 2016] 幸运数字
题目大意 给定一棵\(n\)个点的树,每个点有权值 \(q\)次询问树上路径中 每个点权值可选可不选的最大异或和 \(n\le 2*10^4,q\le 2*10^5,val[i]\le 2^{60}\ ...
- [LOJ 2083][UOJ 219][BZOJ 4650][NOI 2016]优秀的拆分
[LOJ 2083][UOJ 219][BZOJ 4650][NOI 2016]优秀的拆分 题意 给定一个字符串 \(S\), 求有多少种将 \(S\) 的子串拆分为形如 AABB 的拆分方案 \(| ...
- [BZOJ 4455] [ZJOI 2016] 小星星 (树形dp+容斥原理+状态压缩)
[BZOJ 4455] [ZJOI 2016] 小星星 (树形dp+容斥原理+状态压缩) 题面 给出一棵树和一个图,点数均为n,问有多少种方法把树的节点标号,使得对于树上的任意两个节点u,v,若树上u ...
- SCOI 2016 萌萌哒
SCOI 2016 萌萌哒 solution 有点线段树的味道,但是并不是用线段树来做,而是用到另外一个区间修改和查询的利器--ST表 我们可以将一个点拆成\(logN\)个点,分别代表从点\(i\) ...
- 【BZOJ 4568】【SCOI 2016】幸运数字
写了一天啊,调了好久,对拍了无数次都拍不出错来(数据生成器太弱了没办法啊). 错误1:把线性基存成结构体,并作为函数计算,最后赋值给调用函数的变量时无疑加大了计算量导致TLE 错误2:像这种函数(A, ...
- BZOJ.4572.[SCOI2016]围棋(轮廓线DP)
BZOJ 洛谷 \(Description\) 给定\(n,m,c\).\(Q\)次询问,每次询问给定\(2*c\)的模板串,求它在多少个\(n*m\)的棋盘中出现过.棋盘的每个格子有三种状态. \( ...
- 【BZOJ 4569】【SCOI 2016】萌萌哒
http://www.lydsy.com/JudgeOnline/problem.php?id=4569 用ST表表示所有区间,根据ST表中表示的区间长度种一棵nlogn的树,类似线段树,每个节点的左 ...
- 【BZOJ 4571】【SCOI 2016】美味
http://www.lydsy.com/JudgeOnline/problem.php?id=4571 这道题因为有加法,不能像可持久化trie那样每次判断只判断一个子树,而是在主席树上查询\(\l ...
- 【BZOJ 4570】【SCOI 2016】妖怪
http://www.lydsy.com/JudgeOnline/problem.php?id=4570 对于每个妖怪的两个值,看成二位平面上的一个点的横纵坐标(x,y). 因为只关心a/b,所以设经 ...
随机推荐
- 「6月雅礼集训 2017 Day7」回转寿司
[题目大意] 给一个n个数的序列,q次操作,每次选择区间$[l,r]$,给出数p,对于区间$[l,r]$的每个数$x$,做如下操作: 如果$x > p$,就交换$x$和$p$.求每次操作后$p$ ...
- CodeForces 316D3 PE Lesson
time limit per test 3 seconds memory limit per test 256 megabytes input standard input output standa ...
- [BZOJ1177][BZOJ1178][BZOJ1179]APIO2009解题报告
抱着好奇心态去开始做APIO的往年试题感受一下难度 Oil Description 采油区域 Siruseri政府决定将石油资源丰富的Navalur省的土地拍卖给私人承包商以建立油井.被拍卖的整块土地 ...
- 【BZOJ】1609: [Usaco2008 Feb]Eating Together麻烦的聚餐
[算法]动态规划 [题解]DP有个特点(递推的特点),就是记录所有可能状态然后按顺序转移. 最优化问题中DP往往占据重要地位. f[i][j]表示前i头奶牛,第i头改为号码j的最小改动数字,这样每头奶 ...
- [Unity]模拟雨水的折射效果
用GrabPass做的小玩具. 并不是真的计算了折射,只是简单地扰动了uv,对于雨水来说效果已经足够好了. Shader代码: Shader "Unlit/Rain" { Prop ...
- bzoj 1179 tarjan+spfa
首先我们可以将这个图缩成DAG,那么问题中的路线就可以简化为DAG中的一条链,那么我们直接做一遍spfa就好了. 反思:开始写的bfs,结果bfs的时候没有更新最大值,而是直接赋的值,后来发现不能写b ...
- crontab 详解 -- (转)
cron 是一个可以用来根据时间.日期.月份.星期的组合来调度对重复任务的执行的守护进程. cron 假定系统持续运行.如果当某任务被调度时系统不在运行,该任务就不会被执行. 要使用 cron 服务, ...
- hdu 3371(prim算法)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3371 Connect the Cities Time Limit: 2000/1000 MS (Jav ...
- Python 16进制与字符串的转换
电脑上装了Python2.7和3.3两个版本,平时运行程序包括在Eclipse里面调试都会使用2.7,但是由于某些原因在cmd命令行中输入python得到的解释器则是3.3, 一直没对此做处理,因为这 ...
- 下载 LFS所需要的源码包的脚本程序及检验方法
下载 LFS所需要的源码包的脚本程序及检验方法 http://blog.csdn.net/yygydjkthh/article/details/45315143