Address
https://www.lydsy.com/JudgeOnline/problem.php?id=1566
Solution
下面增加一个定义:
「
生成的颜色序列」表示上管道前
个珠子和下管道前
个珠子移到输出管道生成的颜色序列。
想了一波,写完后发现和标解不一样
首先容易定义出一个状态:
表示上管道前
个珠子和下管道
个珠子组成的不同序列的方案数平方和。
边界显然
。
如果上管道的第
个珠子与下管道的第
个珠子异色,那么对于任一上管道前
个珠子和下管道前
个珠子生成的颜色序列
和 上管道
个珠子及下管道前
个珠子生成的颜色序列
,都有
,
不可能与
相同。
这时转移:
否则如果 , 生成 的方案数为 , 生成 的方案数为 ,那么 生成 的方案数应为 而不是 。
所以还要定义状态 ,表示:
上管道的前 个珠子和下管道的前 个珠子生成的序列 ,以及上管道的前 个珠子和下管道的前 个珠子生成的序列 ,对于所有 , 生成 的方案数乘以 生成 的方案数之和。
先从 转移讨论:
如果上管道第 个珠子和第 个珠子不同色,那么 和 不可能用这种方式生成相同的颜色序列。
根据
我们可以把状态定义中的乘积进行拆分,拆分成 个乘积的和。
也就是说,设 表示 生成 的方案数, 那么显然有:
于是转移也就得出了:
(如果上管道第 个珠子和第 个珠子同色)
(如果下管道第 个珠子和上管道第 个珠子同色)
(如果上管道第 个珠子和下管道第 个珠子同色)
(如果下管道第 个珠子和第 个珠子同色)
回到 时 的转移:
最后结果:
注意滚动。
Code
// luogu-judger-enable-o2
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define For(i, a, b) for (i = a; i <= b; i++)
using namespace std;
const int N = 505, ZZQ = 1024523;
int n, m, g[2][N][N], f[N][N];
char s[N], t[N];
int main() {
int i, j, k;
cin >> n >> m;
scanf("%s%s", s + 1, t + 1);
For (i, 0, n) For (j, 0, m) {
int o = i & 1;
For (k, 0, min(n, i + j)) {
if (!i && !j && !k) {g[o][j][k] = 1; continue;}
g[o][j][k] = 0; int h = i + j - k;
if (i && k && s[i] == s[k]) g[o][j][k] += g[o ^ 1][j][k - 1];
if (j && k && t[j] == s[k]) g[o][j][k] += g[o][j - 1][k - 1];
if (i && h && s[i] == t[h]) g[o][j][k] += g[o ^ 1][j][k];
if (j && h && t[j] == t[h]) g[o][j][k] += g[o][j - 1][k];
g[o][j][k] %= ZZQ;
}
if (!i && !j) f[i][j] = 1;
else {
f[i][j] = 0;
if (i) f[i][j] += f[i - 1][j];
if (j) f[i][j] += f[i][j - 1];
if (s[i] == t[j]) f[i][j] += g[o ^ 1][j][i] << 1;
f[i][j] %= ZZQ;
}
}
cout << f[n][m] << endl;
return 0;
}