Description:
有两种珠子,有两个管道,每个管道里有一些珠子,每次可以从上面或下面取珠子构成序列,问构成相同序列的操作对数。
Solution:
考虑
dp[len][i][j]
d
p
[
l
e
n
]
[
i
]
[
j
]
表示当前取了
len
l
e
n
个珠子,第一个操作从上面取了
i
i
个,第二个操作从上面取了个且构成序列相同的方案数,
dp
d
p
即可。
这类题的套路是把平方转化为对数进行统计。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 505;
int n, m;
int dp[2][maxn][maxn];
char s[maxn], t[maxn];
void u(int &x, int y) {
x = (x + y) % 1024523;
}
int main() {
scanf("%d%d%s%s", &n, &m, s + 1, t + 1);
reverse(s + 1, s + n + 1);
reverse(t + 1, t + m + 1);
dp[0][0][0] = 1;
for(int N = 0, pre = 0; N < n + m; ++N, pre ^= 1) {
memset(dp[pre ^ 1], 0, sizeof(dp[pre ^ 1]));
for(int i = 0; i <= N && i <= n; ++i) {
for(int j = 0; j <= N && j <= n; ++j) {
if(s[i + 1] == s[j + 1]) {
u(dp[pre ^ 1][i + 1][j + 1], dp[pre][i][j]);
}
if(s[i + 1] == t[N - j + 1]) {
u(dp[pre ^ 1][i + 1][j], dp[pre][i][j]);
}
if(t[N - i + 1] == s[j + 1]) {
u(dp[pre ^ 1][i][j + 1], dp[pre][i][j]);
}
if(t[N - i + 1] == t[N - j + 1]) {
u(dp[pre ^ 1][i][j], dp[pre][i][j]);
}
}
}
}
printf("%d\n", dp[(n + m) & 1][n][n]);
return 0;
}