codevs 1862 最长公共子序列(求最长公共子序列长度并统计最长公共子序列的个数)

简介: 题目描述 Description字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列,使得对所有的j=0,1,…,k-1,有xij = yj。
题目描述 Description

字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X的子序列,存在X的一个严格递增下标序列<i0,i1,…,ik-1>,使得对所有的j=0,1,…,k-1,有xij = yj。例如,X=“ABCBDAB”,Y=“BCDB”是X的一个子序列。

对给定的两个字符序列,求出他们最长的公共子序列长度,以及最长公共子序列个数。

输入描述 Input Description

第1行为第1个字符序列,都是大写字母组成,以”.”结束。长度小于5000。

第2行为第2个字符序列,都是大写字母组成,以”.”结束,长度小于5000。

输出描述 Output Description

第1行输出上述两个最长公共子序列的长度。

第2行输出所有可能出现的最长公共子序列个数,答案可能很大,只要将答案对100,000,000求余即可。

样例输入 Sample Input

ABCBDAB.
BACBBD.

样例输出 Sample Output

4
7

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;  
 5 
 6 #define maxn 5010  
 7 #define MOD 100000000  
 8 char A[maxn],B[maxn],cur;
 9 int f[2][maxn], g[2][maxn];
10    
11 int main()
12 {  
13     scanf("%s%s", A + 1, B + 1);
14     int na = strlen(A + 1), nb = strlen(B + 1);
15     A[na--] = '\0'; B[nb--] = '\0';
16     
17     cur=0;
18     for(int i = 1; i <= nb; i++) g[0][i] = 1;
19     g[0][0] = g[1][0] = 1;
20     
21     for(int i = 1; i <= na; i++)
22     {
23         cur ^= 1;  
24         for(int j = 1; j <= nb; j++)
25         {
26             if(A[i] == B[j]) f[cur][j] =f[cur^1][j-1] + 1;
27             else f[cur][j] = max(f[cur^1][j], f[cur][j-1]);
28             
29             g[cur][j] = 0;
30             if(f[cur][j] == f[cur^1][j]) g[cur][j] += g[cur^1][j];  
31             if(f[cur][j] == f[cur][j-1]) g[cur][j] += g[cur][j-1];  
32             if(f[cur][j] == f[cur^1][j] && f[cur][j] == f[cur][j-1] && f[cur^1][j-1] == f[cur][j]) 
33                 g[cur][j] -= g[cur^1][j-1];
34             if(A[i] == B[j] && f[cur][j] == f[cur^1][j-1] + 1) g[cur][j] += g[cur^1][j-1];  
35             if(g[cur][j] > MOD) g[cur][j] %= MOD;
36             if(g[cur][j] < 0) g[cur][j] = (g[cur][j] % MOD) + MOD;
37         }
38     }
39     printf("%d\n%d\n", f[cur][nb], g[cur][nb]);  
40     return 0;  
41 }

参考1:http://blog.csdn.net/moep0/article/details/52760974

参考2:http://blog.csdn.net/litble/article/details/67640655

 

算法分析:

第一个问题可以参考最长公共子序列原题的题解。

 第二个问题可以阅读参考1参考2的分析和代码自己理解。

这里摘抄参考1里面的两段代码留存:

代码一:使用了滚动数组。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <cmath>
 5 #include <stack>
 6 #include <vector>
 7 #include <queue>
 8 #include <cstring>
 9 #include <string>
10 #include <map>
11 #include <set>
12 using namespace std;
13  
14 const int BufferSize = 1 << 16;
15 char buffer[BufferSize], *Head, *Tail;
16 inline char Getchar() {
17     if(Head == Tail) {
18         int l = fread(buffer, 1, BufferSize, stdin);
19         Tail = (Head = buffer) + l;
20     }
21     return *Head++;
22 }
23 int read() {
24     int x = 0, f = 1; char c = Getchar();
25     while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
26     while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
27     return x * f;
28 }
29  
30 #define maxn 5010
31 #define MOD 100000000
32 char A[maxn], B[maxn], cur;
33 int f[2][maxn], g[2][maxn];
34  
35 int main() {
36     scanf("%s%s", A + 1, B + 1);
37     int na = strlen(A + 1), nb = strlen(B + 1);
38     A[na--] = '\0'; B[nb--] = '\0';
39      
40     for(int i = 1; i <= nb; i++) g[0][i] = 1; g[0][0] = g[1][0] = 1;
41     for(int i = 1; i <= na; i++) {
42         cur ^= 1;
43         for(int j = 1; j <= nb; j++) {
44             f[cur][j] = max(f[cur^1][j], f[cur][j-1]);
45             if(A[i] == B[j]) f[cur][j] = max(f[cur][j], f[cur^1][j-1] + 1);
46             g[cur][j] = 0;
47             if(f[cur][j] == f[cur^1][j]) g[cur][j] += g[cur^1][j];
48             if(f[cur][j] == f[cur][j-1]) g[cur][j] += g[cur][j-1];
49             if(f[cur][j] == f[cur^1][j] && f[cur][j] == f[cur][j-1] && f[cur^1][j-1] == f[cur][j]) g[cur][j] -= g[cur^1][j-1];
50             if(A[i] == B[j] && f[cur][j] == f[cur^1][j-1] + 1) g[cur][j] += g[cur^1][j-1];
51             if(g[cur][j] > MOD) g[cur][j] %= MOD;
52             if(g[cur][j] < 0) g[cur][j] = (g[cur][j] % MOD) + MOD;
53         }
54     }
55      
56     printf("%d\n%d\n", f[cur][nb], g[cur][nb]);
57      
58     return 0;
59 }
View Code

代码二:不使用滚动数组,假如测试数据较小,可以AC。

 1 #include<iostream>
 2 #include<algorithm>
 3 #include<cmath>
 4 #include<cstring>
 5 #include<cstdio>
 6 #define mod 100000000
 7 using namespace std;
 8 string a,b;
 9 int f[5005][5005],g[5005][5005];
10 int main(){
11     cin>>a>>b;
12     int l1=a.length()-1,l2=b.length()-1;
13     a=' '+a,b=' '+b;
14     for(int i=0;i<=l1;i++)g[i][0]=1;
15     for(int i=0;i<=l2;i++)g[0][i]=1;
16     for(int i=1;i<=l1;i++)
17       for(int j=1;j<=l2;j++)
18         {
19               if(a[i]==b[j])
20               {
21                   f[i][j]=f[i-1][j-1]+1;
22                 g[i][j]=g[i-1][j-1];
23                 if(f[i][j]==f[i][j-1])g[i][j]=(g[i][j]+g[i][j-1])%mod;
24                 if(f[i][j]==f[i-1][j])g[i][j]=(g[i][j]+g[i-1][j])%mod;    
25             }
26               else 
27               {
28                   f[i][j]=max(f[i-1][j],f[i][j-1]);
29                   if(f[i][j]==f[i-1][j])g[i][j]=(g[i][j]+g[i-1][j])%mod;
30                 if(f[i][j]==f[i][j-1])g[i][j]=(g[i][j]+g[i][j-1])%mod;
31                 if(f[i][j]==f[i-1][j-1])g[i][j]-=g[i-1][j-1],g[i][j]=(g[i][j]+mod)%mod;
32             }
33         }
34     cout<<f[l1][l2]<<endl<<g[l1][l2]%mod;
35     return 0;
36 }
View Code

 

相关文章
|
11月前
|
机器学习/深度学习 存储
深入理解SVM中的核函数及其应用
深入理解SVM中的核函数及其应用
437 83
|
7月前
|
缓存 监控 搜索推荐
【实战解析】smallredbook.item_get_video API:小红书视频数据获取与电商应用指南
本文介绍小红书官方API——`smallredbook.item_get_video`的功能与使用方法。该接口可获取笔记视频详情,包括无水印直链、封面图、时长、文本描述、标签及互动数据等,并支持电商场景分析。调用需提供`key`、`secret`和`num_iid`参数,返回字段涵盖视频链接、标题、标签及用户信息等。同时,文章提供了电商实战技巧,如竞品监控与个性化推荐,并列出合规注意事项及替代方案对比。最后解答了常见问题,如笔记ID获取与视频链接时效性等。
|
8月前
|
数据采集 Java 数据处理
Python实用技巧:轻松驾驭多线程与多进程,加速任务执行
在Python编程中,多线程和多进程是提升程序效率的关键工具。多线程适用于I/O密集型任务,如文件读写、网络请求;多进程则适合CPU密集型任务,如科学计算、图像处理。本文详细介绍这两种并发编程方式的基本用法及应用场景,并通过实例代码展示如何使用threading、multiprocessing模块及线程池、进程池来优化程序性能。结合实际案例,帮助读者掌握并发编程技巧,提高程序执行速度和资源利用率。
363 0
|
11月前
|
Linux 数据安全/隐私保护
linux权限管理
本文介绍了Linux系统中的权限管理,包括权限的概念、用户和用户组与权限的关系、文件权限位的说明以及rwx权限的具体含义。同时,详细讲解了如何使用`chmod`和`chown`命令更改文件和目录的权限,并通过多个实验演示了不同权限组合对文件和目录的实际影响。最后,总结了文件和目录权限的一些重要知识点,帮助读者更好地理解和应用Linux权限管理。
388 1
linux权限管理
|
数据采集 JavaScript 前端开发
利用无头浏览器进行APP提取数据的技术与实践
利用无头浏览器进行APP提取数据的技术与实践
|
机器学习/深度学习 弹性计算 运维
阿里云ecs云服务器和轻量级应用服务器有什么区别?
阿里云ecs云服务器和轻量级应用服务器有什么区别?
552 0
考研高数之无穷级数题型三:将函数展开成幂级数和傅里叶级数(题目讲解)
考研高数之无穷级数题型三:将函数展开成幂级数和傅里叶级数(题目讲解)
372 0
|
前端开发 JavaScript
JavaScript 监听移动端横竖屏状态的几种方式
JavaScript 监听移动端横竖屏状态的几种方式
1033 0
JavaScript 监听移动端横竖屏状态的几种方式
|
缓存 Ubuntu Linux
安装HElib并运行示例程序
安装HElib并运行示例程序
安装HElib并运行示例程序
|
存储 算法 Java
12 张图带你彻底理解 ZGC
12 张图带你彻底理解 ZGC
833 1
12 张图带你彻底理解 ZGC