題意
給定 \(n\) 個長度為 \(m\) 的字串,進行若干操作,求每個字串 \(S_a\) 到 \(S_b\) 的方案數。
另外,你還有一個模式串 \(T\),由 \({1, ..., n}\) 與 \(0\)(萬用字元) 組成。
- 從 \(S_x\) 右邊的串開始,不斷向右移動,直到 \(S_y\) 與 \(T\) 匹配。
- 從 \(S_x\) 左邊的串開始,不斷向左移動,直到 \(S_y\) 與 \(T\) 匹配。
- 將 \(T\) 任意一個字元為 \(0\) 的位置改為 \({1, ..., n}\)。從當前串開始,不斷往右移動,直到 \(S_y\) 與 \(T\) 匹配。
- 將 \(T\) 任意一個字元改為 \(0\),不移動。
\(m \le 5, n \le 500\)
Sol
trivial 地,考慮如何用一個狀態表示當前的 \(T\)。
不難發現當前 \(T\) 一定和 \(S_x\) 匹配,那麼我們只需要狀壓記錄當前 \(T\) 哪些位置是 \(0\) 就行了。
考慮對於每個起點跑 \(bfs\)。
前兩個操作可以簡單預處理,而第三個操作需要 \(n \times m\) 的複雜度進行轉移。
總複雜度為 \(n ^ 3 2 ^ m m\)。
直接卡常草過去。
Code
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <queue>
#include <vector>
#include <bitset>
/* #define int long long */
#define pii pair <int, int>
#define il inline
#define rg register
using namespace std;
#ifdef ONLINE_JUDGE
#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;
#endif
il int read() {
rg int p = 0, flg = 1;
rg char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') flg = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
p = p * 10 + c - '0';
c = getchar();
}
return p * flg;
}
void write(int x) {
if (x < 0) {
x = -x;
putchar('-');
}
if (x > 9) {
write(x / 10);
}
putchar(x % 10 + '0');
}
bool _stmer;
#define fi first
#define se second
const int N = 505, M = 6, K = 1 << 5;
array <array <int, M>, N> s;
array <array <int, K>, N> pre, suf;
il bool check(int T, int m, int x, int y){
rg bool flg = 1;
for (rg int k = 1; k <= m; k++)
if (!(T & (1 << (k - 1))))
flg &= (s[x][k] == s[y][k]);
return flg;
}
array <array <array <vector <int>, M>, K>, N> isl;
array <array <int, K>, N> dis;
queue <pii> q;
il void bfs(int st, int n, int m) {
for (int i = 1; i <= n; i++)
dis[i].fill(-1);
for (int i = 0; i < 1 << m; i++)
q.push(make_pair(st, i)), dis[st][i] = 0;
while (!q.empty()) {
rg pii u = q.front();
q.pop();
if (!~dis[pre[u.fi][u.se]][u.se])
dis[pre[u.fi][u.se]][u.se] = dis[u.fi][u.se] + 1, q.push(make_pair(pre[u.fi][u.se], u.se));
if (!~dis[suf[u.fi][u.se]][u.se])
dis[suf[u.fi][u.se]][u.se] = dis[u.fi][u.se] + 1, q.push(make_pair(suf[u.fi][u.se], u.se));
for (rg int i = 1; i <= m; i++) {
int tp = u.se ^ (1 << (i - 1));
if (!~dis[u.fi][tp])
dis[u.fi][tp] = dis[u.fi][u.se] + 1, q.push(make_pair(u.fi, tp)), tot++;
if (u.se & (1 << (i - 1))) continue;
for (auto t : isl[u.fi][u.se][i]) {
if (~dis[t][tp]) continue;
dis[t][tp] = dis[u.fi][u.se] + 1;
q.push(make_pair(t, tp));
}
}
}
}
array <array <int, N>, N> ans;
array <bitset <N>, M> vis;
bool _edmer;
int main() {
cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
/* freopen("string.in", "r", stdin); */
/* freopen("string.out", "w", stdout); */
rg int n = read(), m = read();
for (rg int i = 1; i <= n; i++)
for (rg int j = 1; j <= m; j++)
s[i][j] = read();
for (rg int i = 1; i <= n; i++) {
for (rg int T = 0; T < 1 << m; T++) {
for (rg int j = 1; j < n; j++) {
if (check(T, m, i, (i - j + n - 1) % n + 1)) {
pre[i][T] = (i - j + n - 1) % n + 1;
break;
}
}
for (rg int j = 1; j < n; j++) {
if (check(T, m, i, (i + j - 1) % n + 1)) {
suf[i][T] = (i + j - 1) % n + 1;
break;
}
}
for (rg int j = 1; j <= m; j++)
vis[j] = 0, vis[j][s[i][j]] = 1;
for (rg int j = 1; j < n; j++) {
rg int t = (i + j - 1) % n + 1;
for (rg int k = 1; k <= m; k++)
if (check(T, m, i, t) && (T & (1 << (k - 1))) && !vis[k][s[t][k]])
isl[t][T ^ (1 << (k - 1))][k].push_back(i), vis[k][s[t][k]] = 1;
}
}
}
for (rg int i = 1; i <= n; i++) {
bfs(i, n, m);
for (rg int j = 1; j <= n; j++)
ans[j][i] = dis[j][(1 << m) - 1];
}
for (rg int i = 1; i <= n; i++) {
for (rg int j = 1; j <= n; j++)
write(ans[i][j]), putchar(32);
puts("");
}
return 0;
}