Description
Input
第一行包含两个整数n, m,分别表示上下两个管道中球的数目。 第二行为一个AB字符串,长度为n,表示上管道中从左到右球的类型。其中A表示浅色球,B表示深色球。 第三行为一个AB字符串,长度为m,表示下管道中的情形。
Output
仅包含一行,即为 ∑ki=1a2i 除以1024523的余数。
Sample Input
2 1
AB
B
Sample Output
5
HINT
样例即为文中(图3)。共有两种不同的输出序列形式,序列BAB有1种产生方式,而序列BBA有2种产生方式,因此答案为5。
【大致数据规模】
约30%的数据满足 n, m ≤ 12;
约100%的数据满足n, m ≤ 500。
Solution
过了个样例就开心的交了,然后WA(发现又忘取模了= =)
#我有奇怪的DP技巧系列#?
代码非常非常短但是思路很神
要求各种序列方案数的平方和,这个平方感觉很难处理…
但是可以转换一下,假装有两个人独立地各自取球,他们取到完全相同的输出序列,可以用不同的方法,这样方案数就变成了ai^2
用f[i][j][k][l]表示a在上面取了i个球,下面取了j个球,b在上面取了k个球,下面取了l个球
因为此时两人的输出序列形式相同,可以知道i+j=k+l,于是可以省掉1维,O(n^3)
空间n^3如果用滚动数组可以n^2
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#define Mod 1024523
using namespace std;
int n,m;
int f[505][505][505];
char s1[505],s2[505];
int main()
{
scanf("%d%d",&n,&m);
scanf("%s%s",s1+1,s2+1);
f[0][0][0]=1;
for(int i=0;i<=n;i++)
for(int j=0;j<=m;j++)
for(int k=0;k<=n;k++)
{
int l=i+j-k;
if(i&&k&&s1[i]==s1[k])
{
f[i][j][k]+=f[i-1][j][k-1];f[i][j][k]%=Mod;
}
if(i&&l&&s1[i]==s2[l])
{
f[i][j][k]+=f[i-1][j][k];f[i][j][k]%=Mod;
}
if(j&&k&&s2[j]==s1[k])
{
f[i][j][k]+=f[i][j-1][k-1];f[i][j][k]%=Mod;
}
if(j&&l&&s2[j]==s2[l])
{
f[i][j][k]+=f[i][j-1][k];f[i][j][k]%=Mod;
}
}
printf("%d\n",f[n][m][n]);
return 0;
}