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);
}
}

最新文章

  1. tornado+sqlalchemy+celery,数据库连接消耗在哪里
  2. ASP.NET MVC读取XML并使用ViewData显示
  3. CentOS配置FTP(VSFTPD)
  4. SecureCRT配色方案
  5. 设置BootStrap导航条的高度
  6. qosort 使用使用小例子
  7. 关于wordpress忘记密码 找回密码的方式
  8. web项目配置webAppRootKey 获得根目录 .
  9. C陷阱与缺陷(四)
  10. Windows下安装MySQLdb, Python操作MySQL数据库的增删改查
  11. nodejs 代码设计模式1:同步函数变异步
  12. File字节流
  13. 在 JavaScript 中使用构造器函数模拟类
  14. 五、XML与xpath--------------爬取美女图片
  15. 如何实现从Java入门到服务端项目开发的进阶?
  16. django mysql数据库使用自己的User
  17. c++基本数据类型及其取值范围
  18. python---基于memcache的自定义session类
  19. 这些简单实用的Word技巧,你get了吗
  20. Beta阶段第一篇 Scrum 冲刺博客

热门文章

  1. 用 Docker 来构建 Jumpserver
  2. quartz的简介
  3. Java多线程学习(二)synchronized关键字(2)
  4. SQL语句语法简介
  5. ThinkPHP3.1.3 整合 UEditor百度编辑器 图片上传
  6. 1003: FFF团的情侣活动--课程作业--找出N个数字中唯一出现奇数次的数
  7. 【bzoj4551】TJOI2016&amp;HEOI2016树
  8. webview loadRequest
  9. webapi-2 接口参数
  10. MySQL的sql_mode解析与设置