BZOJ.1566.[NOI2009]管道取珠(DP 思路)

BZOJ
洛谷


考虑(a_i^2)有什么意义:两个人分别操作原序列,使得得到的输出序列都为(i)的方案数。(sum a_i^2)就是两人得到的输出序列相同的方案数。
(f[i][j][k])表示第一个人上管道取到了第(i)个球,下管道取到了第(j)个球,第二个人上管道取到了第(k)个球,的方案数。转移很简单。

复杂度(O(n^3))


//2816kb	1072ms
#include <cstdio>
#include <algorithm>
#define mod 1024523
#define Mod(x) x>=mod&&(x-=mod)
#define Add(x,v) (x+=v)>=mod&&(x-=mod)
typedef long long LL;
const int N=505;

int main()
{
	static int f[2][N][N];
	static char A[N],B[N];
	int n,m; scanf("%d%d",&n,&m);
	scanf("%s%s",A+1,B+1);
	std::reverse(A+1,A+1+n), std::reverse(B+1,B+1+m);
	A[n+1]='?', B[m+1]='!';
	int p=0; f[p][0][0]=1;
	for(int i=0; i<=n; ++i,p^=1)
		for(int j=0; j<=m; ++j)
			for(int k=0,v; k<=n; ++k)
				if((v=f[p][j][k]))
				{
					if(A[i+1]==A[k+1]) Add(f[p^1][j][k+1],v);
					if(A[i+1]==B[i+j-k+1]) Add(f[p^1][j][k],v);
					if(B[j+1]==A[k+1]) Add(f[p][j+1][k+1],v);//p不变啊(日常制杖)
					if(B[j+1]==B[i+j-k+1]) Add(f[p][j+1][k],v);
					if(i+j==n+m) return printf("%d
",f[p][m][n]),0;
					f[p][j][k]=0;
				}
	puts("Miaomiaomiao?");

	return 0;
}
原文地址:https://www.cnblogs.com/SovietPower/p/10375509.html