[POI2000] 公共串 - 后缀数组,二分
[POI2000] 公共串
Description
给出几个由小写字母构成的单词,求它们最长的公共子串的长度。
Solution
预处理出后缀数组和高度数组,二分答案 \(k\) ,对于每一个连续的 \(RMQ\) 大于等于 \(k\) 的段,判断其中是否有来源于每一个串的后缀即可。
#include <bits/stdc++.h>
using namespace std;
int n,m=256,sa[1000005],y[1000005],u[1000005],v[1000005],o[1000005],r[1000005],h[1000005],T;
// sa: Suffix Array
// r: Rank Array
// h: Height Array (between sa[i] & sa[i-1])
char str[1000005];
long long ans;
int bel[1000005];
int buf[10];
int main()
{
    string s[6];
    int T;
    cin>>T;
    for(int i=1; i<=T; i++) cin>>s[i];
    int pin=0;
    for(int i=1; i<=T; i++)
    {
        for(int j=1; j<=s[i].length(); j++)
            str[pin+j]=s[i][j-1],
                       bel[pin+j]=i;
        str[pin+s[i].length()+1]='z'+(char)i;
        pin+=s[i].length()+1;
    }
    n=strlen(str+1);
    for(int i=1; i<=n; i++) u[str[i]]++;
    for(int i=1; i<=m; i++) u[i]+=u[i-1];
    for(int i=n; i>=1; i--) sa[u[str[i]]--]=i;
    r[sa[1]]=1;
    for(int i=2; i<=n; i++) r[sa[i]]=r[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]);
    for(int l=1; r[sa[n]]<n; l<<=1)
    {
        memset(u,0,sizeof u);
        memset(v,0,sizeof v);
        memcpy(o,r,sizeof r);
        for(int i=1; i<=n; i++) u[r[i]]++, v[r[i+l]]++;
        for(int i=1; i<=n; i++) u[i]+=u[i-1], v[i]+=v[i-1];
        for(int i=n; i>=1; i--) y[v[r[i+l]]--]=i;
        for(int i=n; i>=1; i--) sa[u[r[y[i]]]--]=y[i];
        r[sa[1]]=1;
        for(int i=2; i<=n; i++) r[sa[i]]=r[sa[i-1]]+((o[sa[i]]!=o[sa[i-1]])||(o[sa[i]+l]!=o[sa[i-1]+l]));
    }
    {
        int i,j,k=0;
        for(int i=1; i<=n; h[r[i++]]=k)
            for(k?k--:0,j=sa[r[i]-1]; str[i+k]==str[j+k]; k++);
    }
    {
        int l=1,r=1e+9;
        for(int i=1; i<=T; i++) r=min(r,(int)s[i].length());
        ++r;
        while(l<r)
        {
            int mid = (l+r)/2;
            int i=1,j=1,flag=0;
            while(i<=n && j<=n)
            {
                j=i;
                while(h[j+1]>=mid) ++j;
                for(int k=1; k<=T; k++) buf[k]=0;
                for(int k=i; k<=j; k++) buf[bel[sa[k]]]=1;
                int fg=1;
                for(int k=1; k<=T; k++) if(buf[k]==0) fg=0;
                if(fg) flag = 1;
                i=j+1;
            }
            if(flag) l=mid+1;
            else r=mid;
        }
        cout<<l-1<<endl;
    }
}
												
											[POI2000] 公共串 - 后缀数组,二分的更多相关文章
- 【BZOJ2946】[Poi2000]公共串 后缀数组+二分
		
[BZOJ2946][Poi2000]公共串 Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l 读入单词 l 计 ...
 - BZOJ 2946: [Poi2000]公共串( 后缀自动机 )
		
一个串建后缀自动机, 其他串在上面跑, 然后用当前串跑的去更新全部 ------------------------------------------------------------------ ...
 - 【bzoj2946】[Poi2000]公共串 后缀自动机
		
[Poi2000]公共串 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 1386 Solved: 620[Submit][Status][Discus ...
 - bzoj3277 串 (后缀数组+二分答案+ST表)
		
常见操作:先把所有串都连到一起,但中间加上一个特殊的符号(不能在原串中/出现过)作为分割 由于全部的子串就等于所有后缀的所有前缀,那我们对于每一个后缀,去求一个最长的前缀,来满足这个前缀在至少K个原串 ...
 - BZOJ 2946 POI2000 公共串 后缀自动机(多串最长公共子串)
		
题意概述:给出N个字符串,每个串的长度<=2000(雾...可能是当年的年代太久远机子太差了),问这N个字符串的最长公共子串长度为多少.(N<=5) 抛开数据结构,先想想朴素做法. 设计一 ...
 - [BZOJ3277/BZOJ3473] 串 - 后缀数组,二分,双指针,ST表,均摊分析
		
[BZOJ3277] 串 Description 现在给定你n个字符串,询问每个字符串有多少子串(不包括空串)是所有n个字符串中至少k个字符串的子串(注意包括本身). Solution 首先将所有串连 ...
 - BZOJ2946 [Poi2000]公共串(后缀自动机)
		
Description 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务: l 读入单词 l 计算最长公共子串的长度 l 输 ...
 - bzoj 2946 [Poi2000]公共串——后缀自动机
		
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2946 对每个串都建一个后缀自动机,然后 dfs 其中一个自动机,记录同步的话在别的自动机上走 ...
 - BZOJ 2946 [Poi2000]公共串 ——后缀自动机
		
任意选择一个串作为模式串,构建出后缀自动机. 然后用其他的串在后缀自动机上跑匹配. 然后就到了理解后缀自动机性质的时候. 在某一个节点的最大值是可以沿着parent树上传的. 然后用dp[i][j]表 ...
 
随机推荐
- 关于javascript中的内置函数
			
(1) parseInt()函数 语法:parseInt(string,[n]) 该函数主要将首位为数字的字符串转化为数字,若该字符串不是以数字开头,则返回NaN; n是用于指出字符串中的数据是几 ...
 - P5367 【模板】康托展开
			
我们的生活充满了未知与玄学 ---------------------------------------- 链接:P5367 ------------------------------------ ...
 - 如何开启音乐二倍速?不下载其他软件【win10】
			
使用windows自带的windows media player开启N倍速 绪言 额……暑假将终,我想起了件事:貌似我忘记帮你们开好二倍速再走了. 可能我回(六班)来的机会也比较少,废话不多说,直接看 ...
 - CF 150E Freezing with Style [长链剖分,线段树]
			
\(sol:\) 给一种大常数 \(n \log^2 n\) 的做法 考虑二分,由于是中位数,我们就二分这个中位数,\(x>=mid\)则设为 \(1\),否则为 \(-1\) 所以我们只需要找 ...
 - pads无模命令
			
W<n>………改变线宽,比如 30. 栅格(Grids) G<xx>………过孔和设计栅格设置.GD<xx>………显示栅格设置.GP………打开或关闭极性栅格.GP r ...
 - Linux 下安装 java
			
yum 安装java 配置环境 /etc/profile export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.242.b08-0.el7_7. ...
 - CMake 复制文件方法
			
我们经常会遇到将第三方库文件复制到项目运行时文件夹,或者将子项目生成的库文件复制到项目运行时文件夹的情况,本文介绍FILE-COPY.add_custom_command.ADD_CUSTOM_TAR ...
 - mysql修改密码、创建用户、开放远程
			
创建密码: MariaDB [(none)]> use mysql; MariaDB [mysql]> UPDATE user SET password=password('newpass ...
 - selenium规避网站监测
			
规避网站监测  现在不少大网站有对selenium采取了监测机制.比如正常情况下我们用浏览器访问淘宝等网站的window.navigator.webdriver的值为undefined.而使用sel ...
 - oracle备份与还原数据
			
一.表数据备份与还原 creat table 备份表 select * from 原表 where insert into 原表 select * from 备份表 二.利用备份 ...