- 要肝出这道题,你需要知道这样一个\(trick.\)
- 如果你要求对于一个什么东西求出现次数的平方,等价于同时进行两次操作,计算过程可以匹配的方案数。
- 这个\(trick\)可以去某次神仙\(yyb\)的暑假一次\(noip\)模拟赛学一下。
话说\(yyb\)那一次是真的毒瘤。话说神仙\(fdf\)当场爆切。
- 那么$ ∑A_i^2$,可以看成取两次得到了相同的串的方案数。
- 这样就很套路了,朴素想法设\(f_{i,j,p,q}\)表示第一次\(a\)串在\(i\),\(b\)串在\(j\)位置,第二次\(a\)串在\(p\),\(b\)串在\(q\)位置。
- 很显然\(i+j=p+q\),那么后面一维度就省掉了,设\(f_{i,j,k}\)表示总长度为\(i\),第一次\(a\)串在\(j\),第二次\(a\)串在\(k\)的方案数。
- 随便讨论转移一下即可,初始\(f_{0,0,0}=1\),复杂度\(O(n^3)\)。
#include<bits/stdc++.h>
#define R register int
using namespace std;
const int N=601;
const int mod=1024523;
int n,m,f[2][N][N];char A[N],B[N];
void add(R &x,R y){x=(x+y>=mod?x+y-mod:x+y);}
int main(){
cin>>n>>m,scanf("%s",A+1),scanf("%s",B+1);
reverse(A+1,A+n+1),reverse(B+1,B+m+1);
R now=1,pre=0;f[now][0][0]=1;
for(R len=1;len<=n+m;++len){
now^=1,pre^=1;
for(R i=max(0,len-m);i<=min(n,len);++i)
for(R j=max(0,len-m);j<=min(n,len);++j)
f[now][i][j]=0;
for(R i=max(0,len-m);i<=min(n,len);++i){
for(R j=max(0,len-m);j<=min(n,len);++j){
R p=len-i,q=len-j;
if(i&&j&&A[i]==A[j])add(f[now][i][j],f[pre][i-1][j-1]);
if(i&&q&&A[i]==B[q])add(f[now][i][j],f[pre][i-1][j]);
if(p&&j&&B[p]==A[j])add(f[now][i][j],f[pre][i][j-1]);
if(p&&q&&B[p]==B[q])add(f[now][i][j],f[pre][i][j]);
}
}
}
cout<<f[now][n][n]<<endl;
return 0;
}