给定一个字符串 A1..n
对于任意一个集合 G1..m 并且 1≤G1<G2<⋯<Gm≤n
那么 AG1..m 就是 A 的一个子串
如:
AABC
就是ABCABC
的一个子串
给定两个字符串 A,B ,求出他们最长的公共子串 C
意思是: C 既是 A 的子串,又是 B 的子串
先给出代码:
#define mod 1000000007
#define N 5010
int n,m,f[N][N],h[N][N],ans;
char s1[N],s2[N];
int main()
{
scanf("%s%s",s1+1,s2+1);
n=strlen(s1+1);
m=strlen(s2+1);
fr(i,1,n)
f[i][0]=1;
fr(i,0,m)
f[0][i]=1;
fr(i,1,n)
s1[i]-='a'-1;
fr(i,1,m)
s2[i]-='a'-1;
fr(i,1,n)
fr(j,1,m)
if(s1[i]==s2[j])
{
h[i][j]=h[i-1][j-1]+1;
f[i][j]=f[i-1][j-1];
if(h[i-1][j]==h[i][j])
f[i][j]=(f[i][j]+f[i-1][j])%mod;
if(h[i][j-1]==h[i][j])
f[i][j]=(f[i][j]+f[i][j-1])%mod;
}
else
{
h[i][j]=max(h[i-1][j],h[i][j-1]);
if(h[i-1][j]==h[i][j])
f[i][j]=(f[i][j]+f[i-1][j])%mod;
if(h[i][j-1]==h[i][j])
f[i][j]=(f[i][j]+f[i][j-1])%mod;
if(h[i-1][j-1]==h[i][j])
f[i][j]=(f[i][j]-f[i-1][j-1]+mod)%mod;
}
printf("%d\n%d\n",h[n][m],f[n][m]);
return 0;
}
hn,m 表示LCS长度
fn,m 表示LCS个数
我们可以得出
hi,j=⎧⎩⎨⎪⎪hi−1,j−1+1max{hi−1,jhi,j−1s1i=s2js1i≠s2j
fi,j 有些复杂,需要考虑许多情况:
我们先设一个函数 p(...)={10...→true...→false
fi,j={fi−1,j−1+p(hi−1,j=hi,j)×fi−1,j+p(hi,j−1=hi,j)×fi,j−1p(hi−1,j=hi,j)×fi−1,j+p(hi,j−1=hi,j)×fi,j−1−p(hi−1,j−1=hi,j)×fi−1,j−1s1i=s2js1i≠s2j
反正我是觉得没看代码直观。
至于这些怎么推出来的,应该是只有最后一条有疑问,反正减就是去重,可以参考NOIP2016Day2T1