洛谷题目传送门

一进来就看到一个多月前秒了此题的ysn和YCB%%%

最长公共子序列的\(O(n^2)\)的求解,Dalao们想必都很熟悉了吧!不过蒟蒻突然发现,用网格图貌似可以很轻松地理解这个东东?

设字符串长度为\(n,m\),那么想象我们有一个\(n+1\)行\(m+1\)列的网格图,只能从左下角往右、上两个方向走。定义每条路径的长度都为\(1\)。记第\(i\)行第\(j\)列为\((i,j)\)。

话说网格图真tm难画

求最长公共子序列本质上是在两个序列中寻找最多的配对,而且这些配对的位置在序列中的位置也要分别递增。

那么,如果\(x_i\)与\(y_j\)相等,那么我们就从\((i-1,j-1)\)向\((i,j)\)连一条边。这在网格图中分明是一条条捷径,那么我们要寻找最长公共子序列,可不可以转化为寻找最短路,或者说寻找经过捷径次数最多的路径呢?

这个模型是很巧妙的,满足了配对的位置在序列中的位置分别递增(因为只能往右、上走)。

那么再看第二问。显然在这个模型中,不同的公共子序列对应的,不是至少有一条边不相同的路径,而是至少有一条捷径不相同的路径。那么这个该怎么DP呢?

设到达\((i,j)\)最多能经过的捷径数(即序列的两个前缀的最长公共子序列长度)为\(mf_{i,j}\),方案数为\(f_{i,j}\)。显然\((i,j)\)可以从\((i-1,j)\)和\((i,j-1)\)转移,如果\(x_i=y_j\)那么还可以从\((i-1,j-1)\)转移(\(mf\)加上\(1\))。依次转移,如果新的\(mf\)更大则直接覆盖原信息,如果\(mf\)相等则\(f\)相加。

然而,再次注意不同路径的定义。那么是不是可能存在这样一种情况:到\((i-1,j-1)\)的一条路径,分别转移给了\((i-1,j)\)和\((i,j-1)\),而再一次转移给了\((i,j)\),没有经过不同的捷径,却计算了两遍!显然只有\(mf_{i-1,j-1}=mf_{i,j}\)的时候上述情况才会发生,那么这时我们从\(f_{i,j}\)减去\(f_{i-1,j-1}\)即可。

思路都清晰了。在开始码DP之前,我们还需要注意这个DP的过程,每行只会从上一行转移,于是使用滚动数组优化空间,防止MLE。

#include<bits/stdc++.h>
#define RG register
#define I inline
#define R RG int
#define G c=getchar()
using namespace std;
typedef long long LL;
const int N=5009,YL=1e8;
char x[N],y[N];
int ff[N],gg[N],mff[N],mgg[N];
int main(){
scanf("%s%s",x+1,y+1);
R n=strlen(x+1)-1,m=strlen(y+1)-1,i,j,*f=ff,*g=gg,*mf=mff,*mg=mgg;
g[0]=1;for(j=0;j<=m;++j)f[j]=1;
for(i=1;i<=n;++i,swap(f,g),swap(mf,mg)){//滚动数组
memset(g +1,0,m<<2);//注意清空
memset(mg+1,0,m<<2);
for(j=1;j<=m;++j){//三方向转移
if(x[i]==y[j])mg[j]=mf[j-1]+1,g[j]=f[j-1];
if(mf[j]>mg[j])mg[j]=mf[j],g[j]=f[j];//覆盖
else if(mf[j]==mg[j])(g[j]+=f[j])%=YL;//相加
if(mg[j-1]>mg[j])mg[j]=mg[j-1],g[j]=g[j-1];
else if(mg[j-1]==mg[j])(g[j]+=g[j-1])%=YL;
if(mf[j-1]==mg[j])(g[j]+=YL-f[j-1])%=YL;//减掉重复的部分
}
}
printf("%d\n%d\n",mf[m],f[m]);
return 0;
}

洛谷P2516 [HAOI2010]最长公共子序列(LCS,最短路)的更多相关文章

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

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

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

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

  3. 洛谷1439:最长公共子序列(nlogn做法)

    洛谷1439:最长公共子序列(nlogn做法) 题目描述: 给定两个序列求最长公共子序列. 这两个序列一定是\(1\)~\(n\)的全排列. 数据范围: \(1\leq n\leq 10^5\) 思路 ...

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

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

  5. P2516 [HAOI2010]最长公共子序列 题解(LCS)

    题目链接 最长公共子序列 解题思路 第一思路: 1.用\(length[i][j]\)表示\(a\)串的前\(i\)个字符与\(b\)串的前\(j\)个字符重叠的最长子串长度 2.用\(num[i][ ...

  6. luogu P2516 [HAOI2010]最长公共子序列

    传送门 首先那个\(O(n^2)\)的dp都会吧,不会自己找博客或者问别人,或是去做模板题(误) 对以下内容不理解的,强势推荐flash的博客 我们除了原来记录最长上升子序列的\(f_{i,j}\), ...

  7. Luogu P2516 [HAOI2010]最长公共子序列 DP

    首先$LIS$显然:$f[i][j]=max(f[i][j-1],f[i-1][j],(a[i]==b[j])*f[i-1][j-1])$ 考虑如何转移数量: 首先,不管$a[i]$是否等于$b[j] ...

  8. P2516 [HAOI2010]最长公共子序列

    传送门 看到数据范围,显然 $n^2$ 的 $dp$... 设 $f[i][j]$ 表示 $A$ 串考虑了前 $i$ 位,$B$ 串考虑了前 $j$ 位,最优情况下的方案数 但是好像没法判断转移来的是 ...

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

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

随机推荐

  1. Identity(三)

    本文摘自木宛城主的 ASP.NET MVC 随想录——开始使用ASP.NET Identity,初级篇 - 木宛城主 - 博客园 由于ASP.NET Membership.ASP.NET Simple ...

  2. Ionic2 App Import BrowserAnimationsModule or NoopAnimationsModule问题

    在开发app的过程中遇见了动画相关方面的问题,具体如下: 解决方法是:在app.module.ts模块中引入BrowserAnimationsModule import { BrowserAnimat ...

  3. 使用while和read命令读取文件内容

    转:使用while和read命令读取文件内容 1.准备数据文件 $cat a.txt 200:2 300:3 400:4 500:5 2.用while循环从文件中读取数据 #!/bin/ksh whi ...

  4. maven docker 插件集成的几个小坑

    昨晚看springboot视频的时候,发现可以使用docker-maven-plugin这个插件直接build出 docker 镜像到远程服务器上,感觉很方便,于是自己也试了一下,但是碰到了几个问题, ...

  5. python-scapy学习笔记-(1)

    主要功能函数sniff sniff(filter="",iface="any",prn=function,count=N) filter参数允许我们对Scapy ...

  6. WinForm多线程+委托防止界面假死

    当有大量数据需要计算.显示在界面或者调用sleep函数时,容易导致界面卡死,可以采用多线程加委托的方法解决 using System; using System.Collections.Generic ...

  7. D. Fun with Integers

    链接 [http://codeforces.com/contest/1062/problem/D] 题意 给你n,让你从2到n这个区间找任意两个数,使得一个数是另一个的因子,绝对值小的可以变为绝对值大 ...

  8. #个人博客作业week2——结对编程伙伴代码复审

    General 1.程序能够顺利地运行.程序通过命令行输入,能够向对应的文件中输出符合要求的题目和答案.程序能够根据用户的不同选择,进行题目的生产或答案的校验,生成出的题目符合参数要求和项目的查重等各 ...

  9. Daily Scrum NO.10

    工作概况 今天是两周正是开发的最后一个工作日,虽然也是编译的DEADLINE,但成员们还是较为积极.计划内的工作基本都能够完成:线程池.异常清理器和动态爬取的功能.异常清理器界面的第一版也在今晚做了出 ...

  10. 《Linux内核分析》第六周笔记 进程的描述和进程的创建

    进程的描述和进程的创建 一.进程的描述 1.进程描述符task_struct数据结构(一) 操作系统的三大功能:进程管理(核心).内存管理.文件系统. 进程控制块PCB——task_struct(进程 ...