bzoj2423[HAOI2010]最长公共子序列

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

posted @ 2016-07-22 21:38  YuanZiming  阅读(237)  评论(0编辑  收藏  举报