一.题目链接
管道取珠
二.题目大意
原生题目极佳.
三.分析
这道题上来一手转化很妙,学到了~~
题目中设 a[i] 为最终序列的某种方案数,而让我们求解的却是 ,很明显我们需要找出两者的关系.
假设我们有两个完全相同且独立的系统,两个人同时进行操作,不难证明,对于某个最终序列 F,两个人操作完成后得到的序列都与 F 相同的方案数即为
经过这一步转化后,我们就可以愉快进行 dp 辣~~(然鹅并不是...)
我们设 dp[i][j][k][l] 为第一个人从管道一取了 i 个球,第一个人从管道二取了 j 个球,第二个人从管道一取了 k 个球,第二个人从管道二取了 l 个球,且当前所构成序列相同的方案数.
But,这样的状态表示时空都会爆掉滴. 由于两个序列相同,那么 i + j == k + l,所以我们可以省略一维,除此之外对第一维进行滚动优化,这样就卡进 AC 的时空啦!
状态转移方程为
if(s[i + 1] == s[k + 1]) f[p^1][j][k + 1] = (f[p^1][j][k + 1] + f[p][j][k]) % mod; if(s[i + 1] == t[l + 1]) f[p^1][j][k] = (f[p^1][j][k] + f[p][j][k]) % mod; if(t[j + 1] == s[k + 1]) f[p][j + 1][k + 1] = (f[p][j + 1][k + 1] + f[p][j][k]) % mod; if(t[j + 1] == t[l + 1]) f[p][j + 1][k] = (f[p][j + 1][k] + f[p][j][k]) % mod;
除此之外呢,还可以加上一点小优化,就像下面这个样纸
if(!f[p][j][k]) continue; if(s[i + 1] == s[k + 1]) f[p^1][j][k + 1] = (f[p^1][j][k + 1] + f[p][j][k]) % mod; if(s[i + 1] == t[l + 1]) f[p^1][j][k] = (f[p^1][j][k] + f[p][j][k]) % mod; if(t[j + 1] == s[k + 1]) f[p][j + 1][k + 1] = (f[p][j + 1][k + 1] + f[p][j][k]) % mod; if(t[j + 1] == t[l + 1]) f[p][j + 1][k] = (f[p][j + 1][k] + f[p][j][k]) % mod;
经测试,时限优化了好多好多!!!
四.代码实现
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int M = (int)5e2; const ll mod = (ll)1024523; const int inf = 0x3f3f3f3f; const double eps = 1e-8; int n, m; char s[M + 5], t[M + 5]; int f[2][M + 5][M + 5]; int main() { // freopen("input.txt", "r", stdin); // freopen("output.txt", "w", stdout); scanf("%d %d", &n, &m); scanf("%s %s", s + 1, t + 1); reverse(s + 1, s + n + 1); reverse(t + 1, t + m + 1); f[0][0][0] = 1; for(int i = 0, p = 0; i <= n; ++i, p ^= 1) { for(int j = 0; j <= m; ++j) { for(int k = 0; k <= n; ++k) { int l = i + j - k; if(l < 0 || l > m) continue; if(!f[p][j][k]) continue; if(s[i + 1] == s[k + 1]) f[p^1][j][k + 1] = (f[p^1][j][k + 1] + f[p][j][k]) % mod; if(s[i + 1] == t[l + 1]) f[p^1][j][k] = (f[p^1][j][k] + f[p][j][k]) % mod; if(t[j + 1] == s[k + 1]) f[p][j + 1][k + 1] = (f[p][j + 1][k + 1] + f[p][j][k]) % mod; if(t[j + 1] == t[l + 1]) f[p][j + 1][k] = (f[p][j + 1][k] + f[p][j][k]) % mod; f[p][j][k] = 0; } } } printf("%d\n", f[(n + 1) & 1][m][n]); return 0; }