题解 CF506E 【Mr. Kitayuta's Gift】
CF506E Mr. Kitayuta's Gift
题意
- 给定一个小写字符串
s 和一个正整数n 。 - 要求在
s 中插入恰好n 个小写字符使其回文的方案数。 -
题解
首先考虑
考虑 dp。设
那么转移有:
此时我们可以得到一个状态数
仔细观察这个 dp,可以发现这实际上是在一个有限状态自动机上匹配的过程。
比如对于
如果真的理解了上面的 dp,会发现这张图中不同颜色的点和不同形态的边与上面的状态和转移一一对应。
这个自动机的节点数依旧是
而对于两条红点数量相同的链,它们对答案的贡献与红点的具体位置无关,因此本质上是一样的,这意味着本质不同的链只有
但我们还要求出有
现在我们有
但还不够,我们要想办法建出一个节点数只有
同样的,如果真的理解了上面的转化,肯定能自己根据这样图脑补出来压缩后的自动机具体长成什么样。
压缩后的自动机点数只有
然而这玩意儿稍微有点卡常,但如果我们把状态转移设计成只能从编号小的往编号大的点转移,那么矩阵乘法时常数可以除以
最后还有一个问题,
唯一的区别在于,在最后一步的时候,包含两个字符的绿点无法再转移到终点。
那么,我们只保留这样的链,同时去掉终点的自环,这样得到的结果就是要去掉的方案数。
代码
const int N = 207, M = 307;
int n, m, k;
char s[N];
bool v[N][N][N];
modint h[N][N][N], f[M], g[M][M], F[M], G[M][M];
inline modint H(int i, int l, int r) {
if (i < 0) return 0;
if (v[i][l][r]) return h[i][l][r];
v[i][l][r] = 1;
if (l == 1 && r == m) return h[i][l][r] = !i;
if (l != 1 && s[l-1] != s[r]) h[i][l][r] += H(i - 1, l - 1, r);
if (r != m && s[l] != s[r+1]) h[i][l][r] += H(i - 1, l, r + 1);
if (l != 1 && r != m && s[l-1] == s[r+1]) h[i][l][r] += H(i, l - 1, r + 1);
return h[i][l][r];
}
inline int ceil(int x) {
return (x >> 1) + (x & 1);
}
inline void mul(modint f[M], modint g[M][M]) {
modint a[M];
for (int j = 1; j <= k; j++)
for (int i = 1; i <= k; i++)
a[i] += f[j] * g[j][i];
for (int i = 1; i <= k; i++) f[i] = a[i];
}
inline void mul(modint g[M][M]) {
modint a[M][M];
for (int i = 1; i <= k; i++)
for (int o = i; o <= k; o++)
for (int j = o; j <= k; j++)
a[i][j] += g[i][o] * g[o][j];
for (int i = 1; i <= k; i++)
for (int j = 1; j <= k; j++)
g[i][j] = a[i][j];
}
inline void ksm(int o) {
while (o) {
if (o & 1) mul(f, g);
mul(g), o >>= 1;
}
}
int main() {
rds(s, m), rd(n), k = m + ceil(m);
for (int i = 0; i < m; i++) {
modint c;
for (int j = 1; j <= m; j++) {
c += H(i, j, j);
if (j != m && s[j] == s[j+1]) c += H(i, j, j + 1);
}
if (i) {
g[i][k-ceil(m-i)] = c, g[i][i] = 24;
if (i != 1) g[i-1][i] = 1;
else f[i] = 1;
} else {
f[m] = c, g[k][k] = 26;
for (int j = m; j < k; j++) g[j][j+1] = 1, g[j][j] = 25;
}
}
if ((n + m) & 1) {
for (int i = 1; i <= k; i++) F[i] = f[i];
for (int i = 1; i <= k; i++)
for (int j = 1; j <= k; j++)
G[i][j] = g[i][j];
}
ksm(ceil(n + m));
if (!((n + m) & 1)) return print(f[k]), 0;
modint ans = f[k];
for (int i = 1; i <= k; i++) f[i] = F[i];
for (int i = 1; i <= k; i++)
for (int j = 1; j <= k; j++)
g[i][j] = G[i][j];
for (int i = 0; i < m; i++) {
modint c;
for (int j = 1; j <= m; j++)
if (j != m && s[j] == s[j+1]) c += H(i, j, j + 1);
if (i) g[i][k-ceil(m-i)] = c;
else f[m] = c, g[k][k] = 0;
}
ksm(ceil(n + m));
print(ans - f[k]);
return 0;
}