【水题】luogu-2679 子串
这道题应该是noip原题,因为dp方程式比较难推,所以也想写个题解好好整理一下。
首先,因为太菜,第一次看到这个题,只能想到暴力拿部分分,连dp都没去想。
后来知道是dp以后,我也想不出转移方程,所以看了题解。
分析:
有dp[i,j,k,x]表示A串前i个字符去匹配B串前j个字符分成k个部分(在x的状态下)
x=0或1,分别表示A串第i位和B串第j位匹不匹配
比较明显,如果a[i]=b[1] f[i,1,1,1]:=1;
所以f[i,1,1,0]:=sum(f[1~i,1,1,1]);
以上是预处理。
接下来进入dp状态转移。
f[i,j,k,1]:=f[i-1,j-1,k-1,1]+f[i-1,j-1,k-1,0]+f[i-1,j-1,k,1];
分别表示A串第i位和B串第j位匹配时,总方案为 A串第i-1位和B串第j-1匹配时取,不匹配,不取 方案之和。
f[i,j,k,0]:=f[i-1,j,k,0]+f[i-1,j,k,1];
表示A串第i位和B串第j位不匹配时,总方案为 A串第i-1位和B串第j位不匹配 和匹配 的方案数之和
现在放上没有加过优化的程序
const p=1000000007; var n,m,kk,i,j,k,s:longint; a,b:ansistring; f:array[0..500,0..50,0..50,0..1]of longint; //f[i,j,k,x]表示A串前i个字符使用k个子串匹配B串前j个字符 //x=0表示第i位不使用,x=0表示第i位使用 begin readln(n,m,kk); readln(a); readln(b); for i:=1 to n do begin f[i,1,1,0]:=s mod p; if a[i]=b[1] then begin f[i,1,1,1]:=1; inc(s); end; for j:=2 to m do for k:=1 to kk do begin if a[i]=b[j] then f[i,j,k,1]:=((f[i-1,j-1,k-1,1]+f[i-1,j-1,k-1,0]) mod p+f[i-1,j-1,k,1]) mod p; f[i,j,k,0]:=(f[i-1,j,k,0]+f[i-1,j,k,1]) mod p; end; end; writeln((f[n,m,kk,0]+f[n,m,kk,1])mod p); end.
然后因为内存的原因,本题需要加滚动数组。
const p=1000000007; var n,m,kk,i,j,k,s,now:longint; a,b:ansistring; f:array[0..1,0..200,0..200,0..1]of longint; //f[i,j,k,x]表示A串前i个字符使用k个子串匹配B串前j个字符 //x=0表示第i位不使用,x=0表示第i位使用 begin readln(n,m,kk); readln(a); readln(b); now:=1; s:=0; for i:=1 to n do begin now:=1-now; fillchar(f[now],sizeof(f[now]),0); f[now,1,1,0]:=s mod p; if a[i]=b[1] then begin f[now,1,1,1]:=1; inc(s); end; for j:=2 to m do for k:=1 to kk do begin if a[i]=b[j] then f[now,j,k,1]:=((f[1-now,j-1,k-1,1]+f[1-now,j-1,k-1,0]) mod p+f[1-now,j-1,k,1]) mod p; f[now,j,k,0]:=(f[1-now,j,k,0]+f[1-now,j,k,1]) mod p; end; end; writeln((f[now,m,kk,0]+f[now,m,kk,1])mod p); end.
2017-10-29 06:55:26 Hathaway