T3 P3290 [SCOI2016]围棋
思路:
补集转化后用kmp优化轮廓线dp,再滚动数组优化空间
代码:
#include <bits/stdc++.h>
using namespace std;
#define re register
#define LL long long
typedef unsigned int uint;
typedef unsigned long long ull;
#define pb push_back
#define mp make_pair
namespace IO {
char _buf[1 << 21], *_p1 = _buf, *_p2 = _buf;
#define ch() \
(_p1 == _p2 && \
(_p2 = (_p1 = _buf) + fread(_buf, 1, 1 << 21, stdin), _p1 == _p2) \
? EOF \
: *_p1++)
inline int in() {
int s = 0, f = 1;
char x = getchar();
for (; x < '0' || x > '9'; x = getchar())
if (x == '-') f = -1;
for (; x >= '0' && x <= '9'; x = getchar()) s = (s * 10) + (x & 15);
return f == 1 ? s : -s;
}
char buf_[1 << 21];
int p1_ = -1;
inline void flush() {
fwrite(buf_, 1, p1_ + 1, stdout);
p1_ = -1;
}
inline void pc(char x) {
if (p1_ == (1 << 21) - 1) flush();
buf_[++p1_] = x;
}
inline void out(int x) {
char k[30];
int pos = 0;
if (!x) {
pc('0');
return;
}
if (x < 0) {
pc('-');
x = -x;
}
while (x) {
k[++pos] = (x % 10) | 48;
x /= 10;
}
for (int i = pos; i; i--) pc(k[i]);
return;
}
inline void out(string x) {
int k = x.size();
for (int i = 0; i < k; i++) pc(x[i]);
}
} // namespace IO
using namespace IO;
const int mod = 1e9 + 7;
int n, m, C, Q;
int all;
char s[2][13];
int fail[2][13], f[2][1 << 12][7][7];
char node[3] = {'W', 'B', 'X'};
inline int power(int s, int c) {
int ans = 1;
for (; c; s = 1ll * s * s % mod, c >>= 1)
if (c & 1) ans = 1ll * ans * s % mod;
return ans;
}
signed main() {
n = in(), m = in(), C = in(), Q = in();
all = power(3, n * m);
while (Q--) {
for (int t = 0; t < 2; t++) {
scanf("%s", s[t] + 1);
for (int i = 2, j = 0; i <= C; i++) {
while (j && s[t][i] != s[t][j + 1]) j = fail[t][j];
if (s[t][i] == s[t][j + 1]) j++;
fail[t][i] = j;
}
}
memset(f, 0, sizeof(f));
f[0][0][0][0] = 1;
int len = m - C + 1;
int M = 1 << len;
int now = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
now ^= 1;
memset(f[now], 0, sizeof(f[now]));
for (int t = 0; t < M; t++) {
for (int u = 0; u <= C; u++) {
for (int v = 0; v <= C; v++) {
if (f[now ^ 1][t][u][v]) {
for (int x = 0; x <= 2; x++) {
int k0 = u;
while (k0 && (k0 == C || s[0][k0 + 1] != node[x]))
k0 = fail[0][k0];
if (s[0][k0 + 1] == node[x]) k0++;
int k1 = v;
while (k1 && (k1 == C || s[1][k1 + 1] != node[x]))
k1 = fail[1][k1];
if (s[1][k1 + 1] == node[x]) k1++;
if (j >= C && k1 == C && (t & 1)) continue;
int New = t;
if (j >= C) {
New >>= 1;
New |= (k0 == C) << (len - 1);
}
f[now][New][k0][k1] =
(f[now][New][k0][k1] + f[now ^ 1][t][u][v]) % mod;
}
}
}
}
}
}
for (int t = 0; t < M; t++) {
for (int j = 0; j <= C; j++) {
for (int k = 0; k <= C; k++) {
if (j || k) {
f[now][t][0][0] = (f[now][t][0][0] + f[now][t][j][k]) % mod;
f[now][t][j][k] = 0;
}
}
}
}
}
int ans = 0;
for (int t = 0; t < M; t++) ans = (ans + f[now][t][0][0]) % mod;
out(((all - ans) % mod + mod) % mod), pc('\n');
}
flush();
return 0;
}