洛谷1758 BZOJ1566 管道取珠题解
一道人类智慧的dp题
首先我们可以将∑ai^2转化为求取两次,两次一样的方案数
然后用f[i][j][k][l]表示第一个人在第一个串中取到i第二个串中取到j
第二个人在一个串中取到k第二个串中取到l的方案数
显然i+j=k+l,所以第四维可以省掉
推出方程后,可以看出f[i][j][k][l]只与f[i]与f[i-1]有关,所以可以用滚动数组优化
// luogu-judger-enable-o2 # include<iostream> # include<cmath> # include<algorithm> # include<cstdio> const int rqy = 1024523; const int mn = 505; char a[mn],b[mn]; int f[5][mn][mn]; inline void cal(int &a,int &b) { a=a+b; if(a>=rqy) a-=rqy; } int n,m; int main() { scanf("%d%d",&n,&m); scanf("%s",a+1); scanf("%s",b+1); int cur=0; f[0][0][0]=1; for(int i=0;i<=n;i++,cur^=1) for(int j=0;j<=m;j++) for(int k=0;k<=n;k++) { if(i+j-k>m || i+j-k<0) continue; if(a[i+1]==a[k+1]) cal(f[cur^1][j][k+1],f[cur][j][k]); if(a[i+1]==b[i+j-k+1]) cal(f[cur^1][j][k],f[cur][j][k]); if(b[j+1]==b[i+j-k+1]) cal(f[cur][j+1][k],f[cur][j][k]); if(b[j+1]==a[k+1]) cal(f[cur][j+1][k+1],f[cur][j][k]); f[cur][j][k]=0; } printf("%d",f[cur][m][n]); return 0; }