题意
题解
序列自动机,原理即记录序列各个位置对应的每一个字符集元素的下一个出现的位置,则从根节点 D F S DFS DFS 即可遍历所有子序列。对于公共子序列问题,将序列 X , Y X, Y X,Y 处理为序列自动机,从根节点沿相同路径 D F S DFS DFS,则遍历的所有路径对应了所有的公共子序列。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxc 58
#define maxn 3015
#define maxl 20
typedef long long ll;
const ll base = 1e18;
struct bigInt
{
int len;
ll *a;
void init()
{
a = new ll[20], len = 0;
memset(a, 0, sizeof(ll) * 20);
}
void operator++()
{
int i = 0;
++a[i];
while (a[i] >= base)
++a[i + 1], a[i] -= base, ++i;
while (a[len])
++len;
}
void operator+=(bigInt &b)
{
int len2 = max(len, b.len);
for (int i = 0; i < len2; i++)
{
a[i] += b.a[i];
if (a[i] >= base)
++a[i + 1], a[i] -= base;
}
len = len2 + (a[len2] ? 1 : 0);
}
void output()
{
for (int i = len - 1; i >= 0; --i)
printf("%lld", a[i]);
}
} dp[maxn][maxn];
int N, M, K, p, nxt_x[maxn][maxc], nxt_y[maxn][maxc];
char X[maxn], Y[maxn], tmp[maxn];
void init(char *s, int len, int nxt[maxn][maxc])
{
for (int i = len; i; --i)
{
memcpy(nxt[i - 1], nxt[i], sizeof(nxt[i]));
nxt[i - 1][s[i] - 'A'] = i;
}
}
void pdfs(int x, int y)
{
printf("%s\n", tmp);
for (int i = 0; i < maxc; i++)
{
if (nxt_x[x][i] && nxt_y[y][i])
{
tmp[p++] = 'A' + i;
pdfs(nxt_x[x][i], nxt_y[y][i]);
tmp[--p] = '\0';
}
}
}
void cdfs(int x, int y)
{
if (dp[x][y].len)
return;
dp[x][y].init();
++dp[x][y];
for (int i = 0; i < maxc; i++)
{
if (nxt_x[x][i] && nxt_y[y][i])
{
cdfs(nxt_x[x][i], nxt_y[y][i]);
dp[x][y] += dp[nxt_x[x][i]][nxt_y[y][i]];
}
}
}
int main()
{
scanf("%d%d", &M, &N);
scanf("%s%s", X + 1, Y + 1);
scanf("%d", &K);
init(X, M, nxt_x);
init(Y, N, nxt_y);
if (K)
{
pdfs(0, 0);
}
cdfs(0, 0);
dp[0][0].output();
return 0;
}