设状态f(a1, b1, a2, b2),如果f(a1, b1, a2, b2) = K,表示存在K对不完全相同的(A, B),使得A方法已经取出了第一个串的前a1个字符及第二个串的前b1个字符,B方法已经取出了第一个串的前a2个字符以及第二个串的前b2个字符,同时A方法与B方法得到的结果相同。
显然,f(a1, b1, a2, b2)可以转移向4个方向:f(a1+1, b1, a2+1, b2),f(a1+1, b1, a2, b2+1),f(a1, b1+1, a2+1, b2),f(a1, b1+1, a2, b2+1),转移可行的前提是对应的字母相同。
最后,f(n, m, n, m)就是问题的答案。递推初态是f(0, 0, 0, 0) = 1.
恩,没错,就是这样,就这么简单.
回过头想想,本题中唯一能用的承受得起的表示状态的东西就只有 操作序列
而怎么用跟操作序列有关的状态求出ans就成了本题关键,将乘法化为加法,对应到两种操作序列上,平方运算自然消除,而且恰好造出了神奇算法.
program ljl; {great dp} {$inline on}
const mo=1024523; maxn=505;
var i,j,k,st,ed,n,m:longint;
a,b:array[1..maxn]of longint;
qa,qb,qc:array[1..1000000]of longint;
f:array[0..maxn,0..maxn,0..maxn]of longint;
v:array[0..maxn,0..maxn,0..maxn]of boolean;
x:char;
procedure update(i,j,k,x:longint); inline;
begin
inc(f[i,j,k],x); if f[i,j,k]>=mo then dec(f[i,j,k],mo);
if not v[i,j,k] then begin
v[i,j,k]:=true; inc(ed); qa[ed]:=i;qb[ed]:=j;qc[ed]:=k;
end;
end;
begin
readln(n,m);
for i:=1 to n do begin
read(x); a[n-i+1]:=ord(x='B');
end;
readln;
for i:=1 to m do begin
read(x); b[m-i+1]:=ord(x='B');
end;
st:=0;ed:=1;qa[1]:=0;qb[1]:=0;qc[1]:=0;f[0,0,0]:=1;v[0,0,0]:=true;
while st<ed do
for st:=st+1 to ed do begin
i:=qa[st];j:=qb[st];k:=qc[st];
if (i<n)and(k<n)and(a[i+1]=a[k+1]) then update(i+1,j,k+1,f[i,j,k]);
if (j<m)and(k<n)and(b[j+1]=a[k+1]) then update(i,j+1,k+1,f[i,j,k]);
if (i<n)and(i+j-k<m)and(a[i+1]=b[i+j+1-k]) then update(i+1,j,k,f[i,j,k]);
if (j<m)and(i+j-k<m)and(b[j+1]=b[i+j+1-k]) then update(i,j+1,k,f[i,j,k]);
end;
writeln(f[n,m,n]);
end.