题意:给出两个串和一个病毒串,要寻找两个串的最长公共子序列,并且病毒串不能是这个子序列形成的串的子串。
思路:要找公共子序列很简单,主要是这个病毒串比价麻烦,需要在LCS的基础上再加一维,表示当前串匹配到的病毒串的位置k,当添加一个字符时,如果失配,这时不能让k直接等于0,而是要用kmp给k一个合理的值。。。这题wa了好久,最后发现居然是一个while写成了if。。。。对自己无语了
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<algorithm> #include<map> #include<queue> #include<stack> #include<cmath> #include<vector> #define inf 0x3f3f3f3f #define Inf 0x3FFFFFFFFFFFFFFFLL #define eps 1e-9 #define pi acos(-1.0) using namespace std; typedef long long ll; const int maxn=100+10; int dp[maxn][maxn][maxn],pre[maxn][maxn][maxn][3]; char s1[maxn],s2[maxn],vir[maxn]; char ans[maxn]; int next[maxn]; inline void getm(int x,int y,int z,int x1,int y1,int z1,int v) { if(dp[x1][y1][z1]+v>dp[x][y][z]) { dp[x][y][z]=dp[x1][y1][z1]+v; pre[x][y][z][0]=x1; pre[x][y][z][1]=y1; pre[x][y][z][2]=z1; } } void getFail(char *P,int *f,int n) { f[0]=f[1]=0; for(int i=1;i<n;++i) { int j=f[i]; while(j>0&&P[i]!=P[j]) j=f[j]; f[i+1]=P[i]==P[j]?j+1:0; } } int main() { //freopen("in.txt","r",stdin); //freopen("out.txt","w",stdout); scanf("%s",s1); scanf("%s",s2); scanf("%s",vir); int n=strlen(s1); int m=strlen(s2); int t=strlen(vir); getFail(vir,next,t); memset(dp,0xff,sizeof(dp)); memset(pre,0xff,sizeof(pre)); dp[0][0][0]=0; for(int i=0;i<=n;++i) for(int j=0;j<=m;++j) for(int k=0;k<t;++k) { getm(i+1,j,k,i,j,k,0); getm(i,j+1,k,i,j,k,0); if(dp[i][j][k]>=0&&s1[i]==s2[j]) { if(s1[i]==vir[k]) { getm(i+1,j+1,k+1,i,j,k,1); } else { int p=next[k]; while(p>0&&s1[i]!=vir[p]) p=next[p]; getm(i+1,j+1,p+(s1[i]==vir[p]),i,j,k,1); } } } int x,y,z,maxv=-1; for(int k=0;k<t;++k) if(dp[n][m][k]>maxv) { maxv=dp[n][m][k]; z=k; } if(maxv<=0) printf("0\n"); else { x=n;y=m; int len=maxv; while(pre[x][y][z][0]!=-1) { int xx,yy,zz; xx=pre[x][y][z][0]; yy=pre[x][y][z][1]; zz=pre[x][y][z][2]; if(x-xx==1&&y-yy==1&&s1[x-1]==s2[y-1]) ans[maxv--]=s1[x-1]; x=xx;y=yy;z=zz; } for(int i=1;i<=len;++i) printf("%c",ans[i]); printf("\n"); } return 0; }