本文版权归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 ",f[tag][m]); g[tag][m]+=mod; g[tag][m]%=mod; printf("%d",g[tag][m]); } int main() { work(); return 0; }