BZOJ2423 [HAOI2010]最长公共子序列

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

 

 

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

 

题目链接:BZOJ2423

正解:DP

解题报告:

  考虑用f[i][j]表示第一个字符序列的前i位与第二个字符序列的前j位的最长公共子序列长度,那么转移的就直接根据这一位是否对应相等转即可:

  f[i][j]=f[i-1][j-1]+1(a[i]=b[j]);f[i][j]=max(f[i][j-1],f[i-1][j])(a[i]!=b[j])。

  第二问有一点麻烦…

  要讨论一下每个取值在哪取到,不能算重了…

  考虑一下f[i][j]和之前的哪些相同,yy一下就可以咯。

 

//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <complex>
using namespace std;
typedef long long LL;
typedef long double LB;
typedef complex<double> C;
const double pi = acos(-1);
const int MAXN = 5011;
const int mod = 100000000;
char ch[MAXN],s[MAXN];
int n,m,f[2][MAXN],g[2][MAXN];

inline int getint(){
    int w=0,q=0; char c=getchar(); while((c<'0'||c>'9') && c!='-') c=getchar();
    if(c=='-') q=1,c=getchar(); while (c>='0'&&c<='9') w=w*10+c-'0',c=getchar(); return q?-w:w;
}

inline void work(){
	scanf("%s",ch+1); scanf("%s",s+1);
	n=strlen(ch+1); m=strlen(s+1); n--; m--;
	for(int i=0;i<=m;i++) g[0][i]=1;//边界!
	int tag=0; g[1][0]=1;
	for(int i=1;i<=n;i++) {
		tag^=1; 
		//memset(f[tag],0,sizeof(f[tag]));
		//memset(g[tag],0,sizeof(g[tag]));
		for(int j=1;j<=m;j++) {
			if(ch[i]==s[j]) {
				f[tag][j]=f[tag^1][j-1]+1;
				g[tag][j]=g[tag^1][j-1];
				g[tag][j]+=(f[tag][j]==f[tag^1][j])*g[tag^1][j];
				g[tag][j]+=(f[tag][j]==f[tag][j-1])*g[tag][j-1];
			}
			else {
				f[tag][j]=max(f[tag][j-1],f[tag^1][j]);
				g[tag][j]=(f[tag][j]==f[tag^1][j])*g[tag^1][j];
				g[tag][j]+=(f[tag][j]==f[tag][j-1])*g[tag][j-1];
				g[tag][j]-=(f[tag][j]==f[tag^1][j-1])*g[tag^1][j-1];
			}
			g[tag][j]%=mod;
		}
	}
	printf("%d\n",f[tag][m]);

	g[tag][m]+=mod; g[tag][m]%=mod;
	printf("%d",g[tag][m]);
}

int main()
{
    work();
    return 0;
}

  

posted @ 2017-03-05 21:01  ljh_2000  阅读(689)  评论(0编辑  收藏  举报