【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,所以设经 ...
随机推荐
- HDU 1548 A strange lift (广搜)
题目链接 Problem Description There is a strange lift.The lift can stop can at every floor as you want, a ...
- python调参神器hyperopt
一.安装 pip install hyperopt 二.说明 Hyperopt提供了一个优化接口,这个接口接受一个评估函数和参数空间,能计算出参数空间内的一个点的损失函数值.用户还要指定空间内参数的分 ...
- 关于Linux下s、t、i、a权限
文件权限除了r.w.x外还有s.t.i.a权限: 首先我们利用umask查看系统的权限为四位,首位就是特殊权限位,SetUID为4,SetGID为2,t为1 [root@iz2ze46xi6pjjj6 ...
- 网络知识===wireshark抓包出现“TCP segment of a reassembled PDU”的解释(载)
网上胡说八道,众说风云,感觉这篇还算靠谱点. 原文链接:http://blog.csdn.net/dog250/article/details/51809566 为什么大家看到这个以后总是会往MSS, ...
- mac系统中实现vitualBox中访问内网端口
第一步,增加外网网段 打开vitualbox后,按管理菜单,点击->主机网络管理器,如图1所示.点击创建,创建下个网络主机. 图1 然后,关掉虚拟机,虚拟机的设置中,找到网络选项卡,然后点击网络 ...
- 深入浅出Node.js(一) - 初识Node.js
1.Node.js将Javascript解决不确定性所使用的事件驱动方式引入了进来,因为JS是一门事件驱动的语言,旨在能够对外界的事件作出响应; 2.Node.js中,所有的有关异步的操作,都在同步操 ...
- Vim常用命令(转)—默写版
1.光标移动 上: 下: 左: 『字母小写』 右: 上一行行首: 『减号』 下一行行首: 行首: 『数字0』 行尾: 单词词尾或后一个单词词尾: 后一个单词词首: 单词词首或前一个单词词首: 跳转到特 ...
- Leetcode 之Binary Tree Postorder Traversal(47)
中序遍历二叉搜索树,得到的是一个有序的结果,找出其中逆序的地方就可以了.如果逆序的地方相邻,只需把逆序的相换即可:如果不相邻,则需要找到第二个逆序对的 第二个元素再做交换. 定义两个指针p和q来指定需 ...
- agc016D - XOR Replace(图论 智商)
题意 题目链接 给出两个长度为\(n\)的数组\(a, b\) 每次可以将\(a\)中的某个数替换为所有数\(xor\)之和. 若\(a\)数组可以转换为\(b\)数组,输出最少操作次数 否则输出\( ...
- MAC Pro 2017款 无线上网慢
MAC Pro 2017款 在无线路由器和MAC相隔一个房间,上网很慢,怀疑是无线路由器有问题,但其他几台老款MAC和PC上网正常.后来将蓝牙关掉,上网就很快了.