[BZOJ2423][HAOI2010]最长公共子序列
[BZOJ2423][HAOI2010]最长公共子序列
试题描述
字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列。令给定的字符序列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的一个子序列。对给定的两个字符序列,求出他们最长的公共子序列长度,以及最长公共子序列个数。
输入
第1行为第1个字符序列,都是大写字母组成,以”.”结束。长度小于5000。
第2行为第2个字符序列,都是大写字母组成,以”.”结束,长度小于5000。
输出
第1行输出上述两个最长公共子序列的长度。
第2行输出所有可能出现的最长公共子序列个数,答案可能很大,只要将答案对100,000,000求余即可。
输入示例
ABCBDAB.
BACBBD.
输出示例
4 7
数据规模及约定
见“输入”
题解
第一问是最裸的最长公共子序列dp;第二问须在第一问基础上加一个计数问题,设 f(i, j) 是第一个串到第 i 位,第二个串到第 j 位的最长公共子序列长度,g(i, j) 为 f(i, j) 取最大值时的方案数,那么只要保证上一步转移前也是最优的情况就可以了,注意减去重复的计数。
记得开滚动数组!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 | #include <iostream> #include <cstdio> #include <algorithm> #include <cmath> #include <stack> #include <vector> #include <queue> #include <cstring> #include <string> #include <map> #include <set> using namespace std; const int BufferSize = 1 << 16; char buffer[BufferSize], *Head, *Tail; inline char Getchar() { if (Head == Tail) { int l = fread(buffer, 1, BufferSize, stdin); Tail = (Head = buffer) + l; } return *Head++; } int read() { int x = 0, f = 1; char c = Getchar(); while (!isdigit(c)){ if (c == '-' ) f = -1; c = Getchar(); } while (isdigit(c)){ x = x * 10 + c - '0' ; c = Getchar(); } return x * f; } #define maxn 5010 #define MOD 100000000 char A[maxn], B[maxn], cur; int f[2][maxn], g[2][maxn]; int main() { scanf( "%s%s" , A + 1, B + 1); int na = strlen(A + 1), nb = strlen(B + 1); A[na--] = '\0' ; B[nb--] = '\0' ; for ( int i = 1; i <= nb; i++) g[0][i] = 1; g[0][0] = g[1][0] = 1; for ( int i = 1; i <= na; i++) { cur ^= 1; for ( int j = 1; j <= nb; j++) { f[cur][j] = max(f[cur^1][j], f[cur][j-1]); if (A[i] == B[j]) f[cur][j] = max(f[cur][j], f[cur^1][j-1] + 1); g[cur][j] = 0; if (f[cur][j] == f[cur^1][j]) g[cur][j] += g[cur^1][j]; if (f[cur][j] == f[cur][j-1]) g[cur][j] += g[cur][j-1]; 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]; if (A[i] == B[j] && f[cur][j] == f[cur^1][j-1] + 1) g[cur][j] += g[cur^1][j-1]; if (g[cur][j] > MOD) g[cur][j] %= MOD; if (g[cur][j] < 0) g[cur][j] = (g[cur][j] % MOD) + MOD; // printf("%d %d: %d %d\n", i, j, f[cur][j], g[cur][j]); } } printf( "%d\n%d\n" , f[cur][nb], g[cur][nb]); return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 深入理解 Mybatis 分库分表执行原理
· 如何打造一个高并发系统?
· .NET Core GC压缩(compact_phase)底层原理浅谈
· 现代计算机视觉入门之:什么是图片特征编码
· .NET 9 new features-C#13新的锁类型和语义
· Spring AI + Ollama 实现 deepseek-r1 的API服务和调用
· 《HelloGitHub》第 106 期
· 数据库服务器 SQL Server 版本升级公告
· 深入理解Mybatis分库分表执行原理
· 使用 Dify + LLM 构建精确任务处理应用