String

来源:互联网 发布:公寓租房软件 编辑:程序博客网 时间:2024/04/30 22:09

Description

有两种字符串S,T。长度分别为n,m。现在需要在S里面有序地选出k个子串,且在T中出现的顺序与这k个子串的顺序相同。问这k个子串最大的长度和

Input

第一行三个数n,m,k
第二行长度为n的S串
第三行长度为m的T串

Output

一个数表示答案

Sample Input

9 12 4
bbaaababb
abbbabbaaaba

Sample Output

7

Data Constraint

30% n<=10,m<=20
100% n,m<=1000 k<=10

分析

一个显然的思路:设f[i][j][k]表示S串匹配到了第i位,j串匹配到了第j位,取了k个子串的最大值。转移:
f[i][j][k]=max{f[i’][j’][k-1]+len}
其中len是要枚举的,i’≤i-len,j’≤j-len。还要判断S[i-len+1,i]与T[j-len+1,j]是否匹配。
这个转移显然是O(n3m2k)

优化

对于一个len,枚举的i’和j’可以看成一个矩形,然后可以设s[i][j][k]=maxf[i][j][k],求这个的总复杂度是O(nmk)(s[i][j][k]=max{s[i][j-1][k],s[i-1][j][k],f[i][j][k]})
然后上面的方程就变成f[i][j][k]=max{s[i-len][j-len][k-1]+len}

进一步优化

我们发现转移的i-len与j-len的差等于i-j,所以对于相同的i-j和k,把所有s[i][j][k]放在一个单调队列里。时间复杂度降至O(nmk)

#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>using namespace std;const int maxn=1005;int n,m,k,s[maxn][maxn][11],data[maxn*2][maxn][10],h[maxn*2][10],t[maxn*2][10],p[maxn][maxn];char S[maxn],T[maxn];int main(){    freopen("string.in","r",stdin); freopen("string.out","w",stdout);    scanf("%d%d%d%s%s",&n,&m,&k,S+1,T+1);    for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++) if (S[i]==T[j]) p[i][j]=p[i-1][j-1]+1;    memset(t,255,sizeof(t));    for (int i=1;i<=n;i++)        for (int j=1;j<=m;j++)        {            int x=i-j+m,f;            for (int T=k-1;T;T--)            {                for (;h[x][T-1]<=t[x][T-1] && i-data[x][h[x][T-1]][T-1]>p[i][j];h[x][T-1]++);                f=(h[x][T-1]<=t[x][T-1])?s[data[x][h[x][T-1]][T-1]][data[x][h[x][T-1]][T-1]-i+j][T-1]+i-data[x][h[x][T-1]][T-1]:0;                s[i][j][T]=max(max(s[i-1][j][T],s[i][j-1][T]),f);                for (;h[x][T]<=t[x][T] && s[data[x][h[x][T]][T]][data[x][h[x][T]][T]-i+j][T]+i-data[x][h[x][T]][T]<=s[i][j][T];h[x][T]++);                data[x][++t[x][T]][T]=i;            }            f=p[i][j];            s[i][j][0]=max(max(s[i-1][j][0],s[i][j-1][0]),p[i][j]);            for (;h[x][0]<=t[x][0] && s[data[x][h[x][0]][0]][data[x][h[x][0]][0]-i+j][0]+i-data[x][h[x][0]][0]<=s[i][j][0];h[x][0]++);            data[x][++t[x][0]][0]=i;        }    int ans=0;    for (int i=0;i<k;i++) ans=max(ans,s[n][m][i]);    printf("%d\n",ans);    fclose(stdin); fclose(stdout);    return 0;}
0 0
原创粉丝点击