【Luogu】P3856公共子串(DP)

  题目链接

  DP。设last[i][j]是第i个串字符'j'所在的最后的位置,f[i][j][k]是第一个串匹配到i,第二个串匹配到j,第三个串匹配到k,最多的公共子串数。

  那么我们三重循环i、j、k,每次更新last数组的值。

  然后在三重循环内部再加一重循环从'a'到'z',枚举公共子串的最后一个字符是什么。

  然后在last里面找到这三个字符最后出现在什么位置,记为nms。

  于是f[i][j][k]=f[n-1][m-1][s-1]+1。

  最后输出答案即可。

  

#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<cctype>
#include<algorithm>

inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

long long f[105][105][105];
char a[1020],b[1020],c[1020];
int x,y,z;
int last[5][200];

int main(){
    scanf("%s%s%s",a+1,b+1,c+1);
    x=strlen(a+1);y=strlen(b+1);z=strlen(c+1);
    for(int i=1;i<=x;++i){
        last[1][a[i]]=i;    memset(last[2],0,sizeof(last[2]));
        for(int j=1;j<=y;++j){
            last[2][b[j]]=j;    memset(last[3],0,sizeof(last[3]));
            for(int k=1;k<=z;++k){
                last[3][c[k]]=k;
                for(int l='a';l<='z';++l){
                    int n=last[1][l],m=last[2][l],s=last[3][l];
                    if(n&&m&&s)    f[i][j][k]+=f[n-1][m-1][s-1]+1;
                }
            }
        }
    }
    printf("%lld",f[x][y][z]);
    return 0;
}

 

posted @ 2017-12-22 09:21  Konoset  阅读(175)  评论(0编辑  收藏  举报