luogu P2516 [HAOI2010]最长公共子序列

传送门

首先那个\(O(n^2)\)的dp都会吧,不会自己找博客或者问别人,或是去做模板题(误)

对以下内容不理解的,强势推荐flash的博客

我们除了原来记录最长上升子序列的\(f_{i,j}\),再记\(g_{i,j}\)表示到\(i,j\)时的最长上升子序列个数,同时设两个字符串为\(A,B\)

\(A_i=B_j\) ,则有\(f_{i,j}=f_{i-1,j-1}+1,g_{i,j}=g_{i-1,j-1}\)

否则\(f_{i,j}=max(f_{i-1,j},f_{i,j-1}),g_{i,j}\)的话看能否从\(f_{i-1,j}\)\(f_{i,j-1}\)转移,如果可以就加上对应的\(g\)

注意,如果\(f_{i,j}=f_{i-1,j-1}\)(等价于\(f_{i,j}=f_{i-1,j}=f_{i,j-1}\)),那么\(g_{i-1,j-1}=g_{i-1,j}=g_{i,j-1}=\frac{1}{2}g_{i,j}\),所以要减去\(g_{i-1,j-1}\)

至于为什么,yyb都没写,我也不好说.,反正要么感性理解(雾),要么打表手玩.还不理解就戳flash吧qwq

// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
#define db double
#define max(a,b) ((a)>(b)?(a):(b))

using namespace std;
const int N=5000+10,mod=100000000;
il LL rd()
{
    re LL x=0,w=1;re char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
int f[2][N],g[2][N],n,m;
char cc[N],ss[N];

int main()
{
  scanf("%s%s",cc+1,ss+1);
  n=strlen(cc+1)-1,m=strlen(ss+1)-1;
  g[0][0]=g[1][0]=1;
  for(int j=1;j<=m;j++) g[0][j]=1;
  int nw=1,la=0;
  for(int i=1;i<=n;i++)
    {
      for(int j=1;j<=m;j++)
        {
    	  f[nw][j]=g[nw][j]=0;
          if(cc[i]==ss[j]) f[nw][j]=f[la][j-1]+1,g[nw][j]=g[la][j-1];
          else f[nw][j]=max(f[nw][j-1],f[la][j]);
          if(f[nw][j]==f[la][j]) g[nw][j]+=g[la][j];
          if(f[nw][j]==f[nw][j-1]) g[nw][j]+=g[nw][j-1];
          if(f[nw][j]==f[la][j-1]) g[nw][j]-=g[la][j-1];
          g[nw][j]%=mod;
        }
      swap(nw,la);
    }
  printf("%d\n%d\n",f[la][m],g[la][m]);
  return 0;
}

posted @ 2018-09-08 15:19  ✡smy✡  阅读(126)  评论(1编辑  收藏  举报