分析:
这道题的难点在于转化。对于这道题,我们要求的东西就相当于有两个人在分别取球,求取出两个序列完全一样的方案数。
这样转化,问题就变得简单多了。我们设f[i][j][k][l]f[i][j][k][l]f[i][j][k][l]为第一个人在第一个串里去了iii个,在第二个串里取了jjj个,第二个人在第一个串里取了kkk个,在第二个串里取了lll个,而且两个序列完全相同的方案数。
N=500N = 500N=500,四维DP肯定会MLE的,这时候我们发现i+j=k+li+ j = k + li+j=k+l,我们可以省去第四维。然而N3N^3N3的空间也是承受不住的,然后我们又发现,第iii个状态只与第i−1i - 1i−1个状态有关,换句话说,我们可以用滚动数组简化第一维。
然后就可以AC啦!(记得开O2,否则会Tle)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int pp = 1024523;
const int N = 505;
int n, m, f[2][N][N];
char s1[N], s2[N];
int main() {
cin >> n >> m;
scanf("%s", s1 + 1);
scanf("%s", s2 + 1);
f[0][0][0] = 1;
for(int i = 0; i <= n; i++) {
int cur = i & 1;
memset(f[cur ^ 1], 0, sizeof(f[cur ^ 1]));
for(int j = 0; j <= m; j++) {
for(int k = 0 ; k <= i + j; k++) {
int l = i + j - k;
if(s1[i + 1] == s1[k + 1]) (f[cur ^ 1][j][k + 1] += f[cur][j][k]) %= pp;
if(s1[i + 1] == s2[l + 1]) (f[cur ^ 1][j][k] += f[cur][j][k]) %= pp;
if(s2[j + 1] == s1[k + 1]) (f[cur][j + 1][k + 1] += f[cur][j][k]) %= pp;
if(s2[j + 1] == s2[l + 1]) (f[cur][j + 1][k] += f[cur][j][k]) %= pp;
}
}
}
cout << f[n & 1][m][n] << endl;
return 0;
}
本文深入探讨了一道组合计数问题的高效解决策略,通过巧妙的四维动态规划(DP)优化和滚动数组技巧,将复杂度显著降低,实现内存与时间的有效平衡。文章详细介绍了如何利用DP的状态转移方程,结合字符串匹配条件,逐步推导出简洁的算法实现,并通过实例代码展示了完整的解决方案。
638

被折叠的 条评论
为什么被折叠?



