bzoj2423[HAOI2010]最长公共子序列
题意:
求两个字符串的最长公共子序列长度和个数。字符串长度均≤5000。
题解:
dp,设f[i][j]表示x串i位到末位,y串j位到末位的最长长度,g[i][j]表示x串i位到末位,y串j位到末位的最长长度的个数,方程:
x[i]==y[j]:f[i][j]=f[i+1][j+1]+1 g[i][j]=g[i+1][j+1]+(f[i][j]==f[i+1][j])*g[i+1][j]+(f[i][j]==f[i][j+1])*g[i][j+1];
x[i]!=y[j]:f[i][j]=max(f[i+1][j],f[i][j+1]);
g[i][j]=(f[i][j]==f[i+1][j])*g[i+1][j]+(f[i][j]==f[i][j+1])*g[i][j+1]-(f[i][j]==f[i+1][j]&&f[i][j]==f[i][j+1]&&f[i][j]==f[i+1][j+1])*g[i+1][j+1];
边界就是g[xn+1][1..yn+1]=1和g[xn][yn+1]=1,滚动一下就行。
反思:蒟蒻wa了好多发,包括红色部分漏了,模的时候没有考虑负数和边界条件写错,但根本原因还是对dp的循环写法的不熟练(以前总是写记忆化搜索,导致现在一要滚动数组就GG),尤其是边界如何处理方面。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 #define dec(i,j,k) for(int i=j;i>=k;i--) 6 #define maxn 6000 7 #define ll long long 8 #define mod 100000000 9 using namespace std; 10 11 char sx[maxn],sy[maxn]; int nx,ny; 12 ll fx[maxn],fy[maxn],gx[maxn],gy[maxn]; 13 int main(){ 14 scanf("%s",sx+1); scanf("%s",sy+1); nx=strlen(sx+1)-1; ny=strlen(sy+1)-1; 15 inc(i,1,ny+1)gx[i]=1; gy[ny+1]=1; 16 dec(i,nx,1){ 17 dec(j,ny,1){ 18 if(sx[i]==sy[j]){ 19 fy[j]=fx[j+1]+1; gy[j]=gx[j+1]+(fy[j]==fx[j])*gx[j]+(fy[j]==fy[j+1])*gy[j+1]; 20 gy[j]%=mod; 21 }else{ 22 fy[j]=max(fx[j],fy[j+1]); 23 gy[j]=(fy[j]==fx[j])*gx[j]+(fy[j]==fy[j+1])*gy[j+1]-(fy[j]==fx[j]&&fy[j]==fy[j+1]&&fy[j]==fx[j+1])*gx[j+1]; 24 gy[j]+=mod; gy[j]%=mod; 25 } 26 } 27 swap(fx,fy); swap(gx,gy); 28 } 29 printf("%lld\n%lld",fx[1],gx[1]); return 0; 30 }
20160722