前言

感觉这几篇仅有的题解都没说清楚,并且有些还是错的,我再发一篇吧。

分析

首先lcs(最长公共子序列)肯定是板子。但这题要求我们不能光记lcs是怎么打的,因为没这部分分,并且另外一个方程的转移要用到状态的定义。在此定义状态:

设题设字符串为\(S\),\(T\),然后定义字符串的前缀\(i\)表示字符串开头至\(i\)位置构成的字符串,例如\(S\)的前缀\(i\)表示\(S_1\sim S_i\)。

\(f(i,j)\)表示\(S\)的前缀\(i\)和\(T\)的前缀\(j\)的lcs的长度,根据广为人知的lcs算法,

\[f(i,j)=\max\left\{f(i-1,j),f(i,j-1),(f(i-1,j-1)+1)*[S_i==T_j]\right\}
\]

前两个转移式子表示不匹配\(S_i\)和\(T_j\),最后的式子表示\(S_i\)和\(T_j\)匹配并将其贡献计入答案。

考虑新状态\(g(i,j)\)表示同上解释的lcs的匹配方式对数。那么如何转移呢?首先若\(f(i,j)\)等于不匹配转移式子,那么就不匹配转移式子对应的\(g\)应计入答案,因为若\(f\)不改变,那么匹配方式及其对数也应不变。然后考虑两种特殊情况:

  1. \[f(i,j)=f(i-1,j-1)\&S_i\neq T_j$$它描述的是$S_i$和$T_j$都不做出贡献而直接转移重复的情况,那么根据容斥原理,就应减去$g(i-1,j-1)$。
    \]

复杂度

时间是\(O(n\cdot m)\)的,没问题。但是朴素代码空间复杂度也是\(O(n\cdot m)\)的,128MB要炸空间,于是要用滚动数组。

代码

借鉴kiddingme12138的,他的代码(以及很多人的)虽然能AC但是有错,即特殊情况2中无论\(f(i,j)\)最终是否等于\(f(i-1,j-1)+1\)只要\(S_i=T_j\)那么就加上\(g(i-1,j-1)\)。望加强数据。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#define rg register
using namespace std; const int MAXN=5e3+7;
const int mod=1e8;
int n,m;
char S[MAXN],T[MAXN];
int f[2][MAXN],g[2][MAXN]; int main()
{
// freopen("lcs.in","r",stdin);
// freopen("lcs.out","w",stdout);
scanf("%s",S+1);
n=strlen(S+1)-1;
scanf("%s",T+1);
m=strlen(T+1)-1;
int cur=0;
for(rg int i=0;i<=m;++i)
g[cur][i]=1;
for(rg int i=0;i<=n;++i)
{
cur^=1;g[cur][0]=1;
for(rg int j=1;j<=m;++j)
{
g[cur][j]=0;
f[cur][j]=max(f[cur^1][j],f[cur][j-1]);
if(S[i]==T[j])
f[cur][j]=max(f[cur][j],f[cur^1][j-1]+1);
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(S[i]==T[j]&&f[cur][j]==f[cur^1][j-1]+1)
g[cur][j]+=g[cur^1][j-1];
if(S[i]!=T[j]&&f[cur][j]==f[cur^1][j-1])
g[cur][j]-=g[cur^1][j-1];
g[cur][j]=(g[cur][j]+mod)%mod;
}
}
printf("%d\n%d",f[cur][m],g[cur][m]);
}

LG2516 【[HAOI2010]最长公共子序列】的更多相关文章

  1. [BZOJ2423][HAOI2010]最长公共子序列

    [BZOJ2423][HAOI2010]最长公共子序列 试题描述 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x ...

  2. 【BZOJ2423】[HAOI2010]最长公共子序列 DP

    [BZOJ2423][HAOI2010]最长公共子序列 Description 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字 ...

  3. 2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组)

    2021.12.10 P2516 [HAOI2010]最长公共子序列(动态规划+滚动数组) https://www.luogu.com.cn/problem/P2516 题意: 给定字符串 \(S\) ...

  4. bzoj:2423: [HAOI2010]最长公共子序列

    Description 字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0, ...

  5. [HAOI2010]最长公共子序列(LCS+dp计数)

    字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干个字符(可能一个也不去掉)后所形成的字符序列.令给定的字符序列X=“x0,x1,…,xm-1”,序列Y=“y0,y1,…,yk-1”是X ...

  6. 洛谷P2516 [HAOI2010]最长公共子序列(LCS,最短路)

    洛谷题目传送门 一进来就看到一个多月前秒了此题的ysn和YCB%%% 最长公共子序列的\(O(n^2)\)的求解,Dalao们想必都很熟悉了吧!不过蒟蒻突然发现,用网格图貌似可以很轻松地理解这个东东? ...

  7. HAOI2010 最长公共子序列

    题目链接:戳我 30分暴力....暴力提取子序列即可qwqwq #include<iostream> #include<cstdio> #include<algorith ...

  8. bzoj 2423: [HAOI2010]最长公共子序列【dp+计数】

    设f[i][j]为a序列前i个字符和b序列前j个字符的最长公共子序列,转移很好说就是f[i][j]=max(f[i-1][j],f[i][j-1],f[i-1][j-1]+(a[i]==b[j])) ...

  9. 洛谷 P2516 [HAOI2010]最长公共子序列

    题目传送门 解题思路: 第一问要求最长公共子序列,直接套模板就好了. 第二问要求数量,ans[i][j]表示第一个字符串前i个字符,第二个字符串前j个字符的最长公共子序列的数量 如果f[i][j]是由 ...

随机推荐

  1. python学习 面向对象高级编程

    ---恢复内容开始--- 面向对象编程---oop,是一种编程思想,oop把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数 ...

  2. 二. Python基础(2)--语法

    二. Python基础(2)--语法 1.实现一个简单的登录系统 '''# 形式1 n = 1 while n < 4:     name = input("请输入姓名\n" ...

  3. 1085 PAT单位排行

    每次 PAT 考试结束后,考试中心都会发布一个考生单位排行榜.本题就请你实现这个功能. 输入格式: 输入第一行给出一个正整数 N(≤10​^5​​),即考生人数.随后 N 行,每行按下列格式给出一个考 ...

  4. Docker(2):快速入门及常用命令

    什么是Docker? Docker 是世界领先的软件容器平台.开发人员利用 Docker 可以消除协作编码时“在我的机器上可正常工作”的问题.运维人员利用 Docker 可以在隔离容器中并行运行和管理 ...

  5. c# 中foreach 循环

    使用foreach循环可以迭代数组或一个集合对象, 1.通过foreach 循环输出整型数组中的数组: 2.通过for循环输出整型数组中的元素: 3.foreach 循环设置数组元素的计算器: cla ...

  6. 框架:Spring IoC

    Spring篇 第二章.Spring IoC简介 一.基本概念 控制反转是一个比较抽象的概念,是Spring框架的核心,用来消减计算机程序的耦合问题. 依赖注入是IoC的另外一种说法,只是从不同的角度 ...

  7. Python 网络通信协议 tcp udp区别

    网络通信的整个流程 在这一节就给大家讲解,有些同学对网络是既熟悉又陌生,熟悉是因为我们都知道,我们安装一个路由器,拉一个网线,或者用无限路由器,连上网线或者连上wifi就能够上网购物.看片片.吃鸡了, ...

  8. flex 布局 出滚动条的操作

    flex布局也是可以初横向滚动条的哦, 设置 flex-wrap:nowrap ,然后横向的固定宽度超过100% 则出滚动条

  9. python文件读写小结

    读文件 打开一个文件用open()方法(open()返回一个文件对象,它是可迭代的): >>> f = open('test.txt', 'r') r表示是文本文件,rb是二进制文件 ...

  10. [JetBrains注册] 利用教育邮箱注册JetBrains产品(pycharm、idea等)的方法

    我们在使用JetBrains的一些产品时,大多使用网上的一些key去注册或者pojie的,但是由于提供这些key的服务器并不能保证稳定可用,所以可能一段时间我们使用的ide又需要重新pojie. 这里 ...