BZOJ 2423: [HAOI2010]最长公共子序列

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2423

题解:唔,我其实也不会,然后去看了题解。。。

大概意思是我们不仅仅用f[i][j]来表示最长公共子序列的长度,还要用一个g[i][j]来表示方案数,具体的话程序里写吧。。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define mod 100000000;
using namespace std;
char a[10000],b[10000];
long long g[2][6000],f[2][6000];
int q,p2,p1,k1,k2,k3;
int main()
{
  scanf("%s%s",a+1,b+1);
  int p1=0;
  int n=strlen(a+1)-1,m=strlen(b+1)-1;//记录输入的长度
  for (int i=0;i<=m;i++) g[0][i]=1;//一边没有,另一边为一个的方案数为1; 
  g[1][0]=1;
//这道题需要用滚动数组,所以我们只需计录之前的状态就可以了
  for (int i=1;i<=n;i++)
  {
       p2=p1; p1=p1^1;
//这里我本来用的是减法,结果悲催的发现时间超限了。。。所以还是乖乖
//用位运算吧,p1表示当前状态,p2表示上一次的状态。
   for (int j=1;j<=m;j++)
    if (a[i]==b[j])//如果说当前相等的话
    {
         f[p1][j]=max(f[p1][j],f[p2][j-1]+1);
//这一次的方案数一定包括f[p2][j-1];
         if (f[p1][j]==f[p1][j-1]) k1=1; else k1=0;
         if (f[p1][j]==f[p2][j]) k2=1; else k2=0;
//继续判断其他情况如果相等的话才能加上相应的方案数
         g[p1][j]=(g[p2][j-1]+k1*g[p1][j-1]+k2*g[p2][j])%mod;
    }
    else 
    {
        f[p1][j]=max(f[p1][j-1],f[p2][j]);
        if (f[p1][j]==f[p1][j-1]) k1=1; else k1=0;
//如果公共序列的长度没变,但是位置已经进行了移动,那就 加上上次的方案数。      
         if (f[p1][j]==f[p2][j]) k2=1; else k2=0;
         if (f[p1][j]==f[p2][j-1]) k3=-1; else k3=0;
         g[p1][j]=(k3*g[p2][j-1]+k1*g[p1][j-1]+k2*g[p2][j])%mod;
    }
  }
  cout<<f[p1][m]<<endl;  cout<<g[p1][m]<<endl;
  return 0;
} 
原文地址:https://www.cnblogs.com/2014nhc/p/6513644.html