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;
}
本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

浙公网安备 33010602011771号