正题

题目链接:https://loj.ac/p/6564


题目大意

给两个序列\(a,b\)求它们的最长公共子序列。

\(1\leq n,m,a_i,b_i\leq 7\times 10^4\)


解题思路

无意间看到的一个\(bitset\)科技。

首先设\(f_{i,j}\)表示\(a\)串匹配到第\(i\)个\(b\)串匹配到第\(j\)个时的最长长度,做过\(dp\)套\(dp\)的应该知道\(f_{i,j}\)的性质。

\[0\leq f_{i,j}-f_{i,j-1}\leq 1
\]

基本的思路就是设\(01\)矩阵\(M\)满足\(f_{i,j}=\sum_{k=1}^jM_{i,k}\)然后用\(bitset\)优化转移

然后考虑一下怎么转移,我们先预处理出\(p\)数组其中\(p_i\)表示数字\(i\)出现的位置集合

我们的转移要把\(M\)中的\(1\)尽量的往前移动并且看能否加上一个新的\(1\)。

假设现在的字符是\(c\),那么我们将使用\(p_c\)进行转移。

我们把\(M\)中每个\(1\)作为结尾分成若干段(最后的\(0\)也是一段,顺序是从低位到高位)。

那么对于一段中如果这一段\(p_c\)有\(1\)那么我们就取最前面的那个\(1\),这样因为前面假设有\(j\)个\(1\)那么这次就匹配\(p_c\)最前面的那个作为\(j+1\)。

但是我们显然不可能一段一段做,我们可以考虑怎么把这个操作转成位运算。

考虑一下我们平时是怎么取一个\(01\)串的第一位的,我们有\(lowbit(x)=((x-1)\ xor\ x)\ and\ x\)对吧。

发现这里每段分开取实际上难实现的地方只有\(x-1\),考虑怎么实现这个问题。

因为\(1\)是段的末尾,所以每一段的开头前面都是\(1\),所以如果我们让\(M\)左移一位那么就变成开头是\(1\)了(需要注意补上第一段的\(1\),所以应该是\((M<<1)+1\))

最后来说是

\[M=(X-(M<<1)+1)\ xor\ X\ and\ X
\]

这样我们就完成了\(M\)的转移,因为需要位运算,所以需要手写\(bitset\)。

时间复杂度\(O(\frac{nm}{\omega})\)

我是看这篇博客学的,看不懂的可以去看下:https://www.cnblogs.com/-Wallace-/p/bit-lcs.html


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ull unsigned long long
using namespace std;
const int N=7e4+10;
int n,m,L;
struct bitset{
ull t[N/64+5];
bitset(){memset(t,0,sizeof(t));return;}
void set(int p){
t[p>>6]|=(1ull<<(p&63));
return;
}
void shift(){
ull last=0;
for(int i=0;i<L;i++){
ull cur=t[i]>>63;
(t[i]<<=1)|=last;
last=cur;
}
return;
}
int count(){
int ans=0;
for(int i=0;i<L;i++)
{ull x=t[i];while(x)x-=(x&-x),ans++;}
return ans;
}
bitset& operator=(const bitset &b)
{memcpy(t,b.t,sizeof(t));return *this;}
bitset& operator|=(const bitset &b){
for(int i=0;i<L;i++)t[i]|=b.t[i];
return *this;
}
bitset& operator&=(const bitset &b){
for(int i=0;i<L;i++)t[i]&=b.t[i];
return *this;
}
bitset& operator^=(const bitset &b){
for(int i=0;i<L;i++)t[i]^=b.t[i];
return *this;
}
}p[N],f,g;
bitset operator-(const bitset &a,const bitset &b){
bitset tmp;ull last=0;
for(int i=0;i<L;i++){
ull cur=(a.t[i]<b.t[i]+last);
tmp.t[i]=a.t[i]-b.t[i]-last;
last=cur;
}
return tmp;
}
int main()
{
scanf("%d%d",&n,&m);L=(n>>6)+1;
for(int i=1,c;i<=n;i++)
scanf("%d",&c),p[c].set(i);
for(int i=1,c;i<=m;i++){
scanf("%d",&c);
(g=f)|=p[c];
f.shift();f.set(0);
f=g-f;f^=g;f&=g;
}
printf("%d",f.count());
return 0;
}

[科技]Loj#6564-最长公共子序列【bitset】的更多相关文章

  1. 【科技】位运算(bitset)优化最长公共子序列算法

    最长公共子序列(LCS)问题 你有两个字符串 \(A,B\),字符集为 \(\Sigma\),求 \(A, B\) 的最长公共子序列. 简单动态规划 首先有一个广为人知的 dp:\(f_{i,j}\) ...

  2. POJ1159——Palindrome(最长公共子序列+滚动数组)

    Palindrome DescriptionA palindrome is a symmetrical string, that is, a string read identically from ...

  3. POJ 1159 Palindrome(最长公共子序列)

    Palindrome [题目链接]Palindrome [题目类型]最长公共子序列 &题解: 你做的操作只能是插入字符,但是你要使最后palindrome,插入了之后就相当于抵消了,所以就和在 ...

  4. 51NOD 1006 最长公共子序列 Lcs 动态规划 DP 模板题 板子

    给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的). 比如两个串为: abcicba abdkscab ab是两个串的子序列,abc也是,abca也是,其中abca是这两个字符串最 ...

  5. [csu/coj 1078]多个序列的最长公共子序列

    题意:给n个序列,同一个序列里面元素互不相同,求它们的最长公共子序列. 思路:任取一个序列,对于这个序列里面的两个数ai,aj(i<j),如果对于其它每一个序列,都出现过ai,aj,且ai在aj ...

  6. 用python实现最长公共子序列算法(找到所有最长公共子串)

    软件安全的一个小实验,正好复习一下LCS的写法. 实现LCS的算法和算法导论上的方式基本一致,都是先建好两个表,一个存储在(i,j)处当前最长公共子序列长度,另一个存储在(i,j)处的回溯方向. 相对 ...

  7. 动态规划之最长公共子序列(LCS)

    转自:http://segmentfault.com/blog/exploring/ LCS 问题描述 定义: 一个数列 S,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则 ...

  8. [Data Structure] LCSs——最长公共子序列和最长公共子串

    1. 什么是 LCSs? 什么是 LCSs? 好多博友看到这几个字母可能比较困惑,因为这是我自己对两个常见问题的统称,它们分别为最长公共子序列问题(Longest-Common-Subsequence ...

  9. 动态规划求最长公共子序列(Longest Common Subsequence, LCS)

    1. 问题描述 子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串 cnblogs belong 比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与 ...

随机推荐

  1. linux命令别名

    p.p1 { margin: 0; font: 20px Menlo; color: rgba(0, 0, 0, 1) } span.s1 { font-variant-ligatures: no-c ...

  2. FastReport.net 绿色破解版winform中使用

    FastReport 是非常有名的报表库,曾经在delphi中经常看到 现在FastReport.net 是.net平台下的实现.它的价格对于个人开发者来说确实非常非常贵 出于学习的目的(0<& ...

  3. 【java虚拟机】分代垃圾回收策略的基础概念

    作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/6602166.html 一.为什么要分代 分代的垃圾回收策略,是基于这样一个事实:不同的对象的生命周期是不一 ...

  4. java中的静态内部类

    静态内部类是 static 修饰的内部类,这种内部类的特点是: 1. 静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问 2. 如果外部类的静态成员与内部类的成 ...

  5. session.flush与transaction.commit

    以session的save方法为例来看一个简单.完整的事务流程,如下是代码片段: ---------------------------- Session session = sessionFacto ...

  6. Java学习之 多态 Polymorphism

    转自:http://www.cnblogs.com/mengdd/archive/2012/12/25/2832288.html 多态的概念 多态==晚绑定. 不要把函数重载理解为多态. 因为多态是一 ...

  7. 【Azure 应用服务】App Service For Windows 环境中部署Python站点后,如何继续访问静态资源文件呢(Serving Static Files)?

    问题描述 当创建一个App Service 后,运行时环境和版本选择Windows 和 Python 3.6. 登录Kudu 站点查看,默认的文件有 web.config, hostingstart- ...

  8. Linux centos7 pstree

    2021-08-12 1.命令简介pstree (display a tree of processes) 命令用于查看进程树之间的关系,即哪个进程是父进程,哪个是子进程,可以直观地看出是谁创建了谁. ...

  9. Android App性能测试之adb命令

    本篇文章总结了Android App性能测试过程中常用的adb命令.通过这些adb命令,可以查看App的性能数据,为评判性能好坏作参考. CPU相关 显示占用CPU最大的5个应用 adb shell ...

  10. AWS EC2 实例 SSH 无法登录故障

    文章链接 故障表现 在使用 jumperver 登录 AWS ec2 实例的时候发现 ssh 配合秘钥登录的时候无法登录, 具体报错如下: ssh -i /path/xx.pem user@10.0. ...