讨论 / 哎呀,这题太神奇了.
a875797040 2013-02-03 00:28:00
点我顶贴 收藏 删除
首先对 ans=sigma(a[i]^2)进行转化,将其这样理解:用A和B分别表示一种取珠的方法,将结果相同的两种取珠方法(不管这两种取珠方法本身是否相同)记为(A, B),不难发现ans就是所有这样的(A, B)的对数。

设状态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就成了本题关键,将乘法化为加法,对应到两种操作序列上,平方运算自然消除,而且恰好造出了神奇算法.

#1 a875797040@2013-02-03 00:28:00
回复 删除
我的代码,交过了但是超时,只过了6个点。

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.

查看更多回复
提交回复