【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; }