Description
设A、B两字符串的最长公共公共前缀长度为L,那么在A串所有长度为L的子串中,有多少个同时是B的子串。
Solution
把题目改成:“A、B串中所有长度为L的子串,有多少个是两两相同的”,那么这个直接用求最长公共子串的DP加上统计方案数即可,注意细节;
那么这题怎么做呢?
设i,j,k,保证
ai=aj,ai=ak,j<k
这三个条件
那么有结论:
fi,j
所记录的方案数是
fi,k
所记录的子集,这个证明显然。
通过这个结论,我们每次统计ans时只要统计 fi,m 的方案即可保证题目要求,
复杂度: O(n2)
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define min(q,w) ((q)>(w)?(w):(q))
using namespace std;
typedef long long LL;
const int N=1050,mo=1e9+7;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n;
int a[N],b[N];
struct qqww
{
int v;
LL f;
}f[N][N],ans;
qqww max(qqww q,qqww w)
{
if(q.v>w.v)return q;
if(q.v<w.v)return w;
q.f=(q.f+w.f)%mo;
return q;
}
void LG()
{
fo(i,0,m)f[0][i].f=1;
f[0][0].f=1;
fo(i,1,n)
{
fo(j,1,m)
{
f[i][j]=f[i][j-1];
if(a[i]==b[j])
{
qqww t=f[i-1][j-1];t.v++;
if(t.v>f[i][j].v)f[i][j]=t;
else if(t.v==f[i][j].v)f[i][j].f=t.f;
}
}
ans=max(ans,f[i][m]);
fo(j,1,m)f[i][j]=max(f[i][j],f[i-1][j]);
f[i][0].f=1;
}
}
int main()
{
int q,w;char ch;
for(ch=getchar();ch<='z'&&ch>='a';ch=getchar())a[++n]=ch-96;
for(;ch<'a'||ch>'z';ch=getchar());
for(;ch<='z'&&ch>='a';ch=getchar())b[++m]=ch-96;
LG();
printf("%d\n",ans.f);
return 0;
}