BZOJ 2806 [Ctsc2012]Cheat (后缀自动机+二分+单调队列+dp)
题目大意:
给你一堆模式串和文本串
对于每个文本串,我们可以把它不可重叠地拆分成很多子串,如果拆分出的串作为子串出现在了任何一个模式串中,我们称它是“眼熟的”,我们必须保证“眼熟的”子串总长度不小于文本串的90%,现在定义一个数$L$,表示拆分出的子串的最小长度,求每个文本串的$L$的最大值
神题
考虑$L$的性质,发现$L$越大,“眼熟的子串”总长度越长
可以这样简单证明,长度越小的串,对于匹配越有利,因为如果一个大串出现在了模式串中,那么它的所有子串一定出现在了模式串中,反之,小串出现在模式串中,几个小串组成的大串却不一定出现在模式串中。
发现了这个性质,我们可以就二分$L$了
每次选择一个长度$L$作为每次拆分出的串的长度下限进行验证
定义$f[i]$表示拆分串$S[1,i]$,拆分出的一些串能在模式串中被识别,这些能被识别的串的最长长度
要么第i位单独被拆出来,并且不被识别,$f[i]=f[i-1]$
要么第i位作为末尾,组成一个能被识别的串,必须保证开头的前一位$j\in[1,i-L]$,$f[i]=f[j]+i-j$
发现$f[i]=f[j]+i-j=(f[j]-j)+i$可以用单调队列优化
能被识别的串长度必须不小于$L$!
预处理,对所有模式串建广义$SAM$
每次把当前文本串放进去跑,预处理出以i为结尾的最长可识别串的长度$ma_{i}$
如果当前节点没有$trs[x][c]$,就要像$fail$树一样不断跳$pre$删掉一部分前缀,直到碰到一个节点有$trs[x][c]$
如果当前节点有$trs[x][c]$,就跳过去。
但现在我们先不能跳过去,因为$trs[x][c]$的信息我们还不知道
现在$dep_{x}$表示的并非当前串的长度,而是在$trs$图里表现的最长长度,由于每次沿$trs$指针移动,长度+1,所以$ma_{i}=min(ma_{i-1}+1,dep[x]+1)$
细节比较多,尤其是单调队列的地方
#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N1 1105000
#define S1 (N1<<1)
#define T1 (N1<<2)
#define ll long long
#define uint unsigned int
#define rint register int
#define dd double
#define il inline
#define inf 0x3f3f3f3f
#define idx(X) (X-'0')
using namespace std; int gint()
{
int ret=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){ret=ret*+c-'';c=getchar();}
return ret*fh;
}
int N,M,len;
char str[N1];
int ma[N1];
namespace SAM{
int trs[S1][],pre[S1],dep[S1],tot,la;
void init(){tot=la=;}
void reduct(){la=;}
void insert(int c)
{
int p=la,np=++tot,q,nq;la=np;
dep[np]=dep[p]+;
for(;p&&!trs[p][c];p=pre[p]) trs[p][c]=np;
if(!p) {pre[np]=;return;}
q=trs[p][c];
if(dep[q]==dep[p]+) pre[np]=q;
else{
pre[nq=++tot]=pre[q];
pre[q]=pre[np]=nq;
dep[nq]=dep[p]+;
memcpy(trs[nq],trs[q],sizeof(trs[q]));
for(;p&&trs[p][c]==q;p=pre[p]) trs[p][c]=nq;
}
}
void get_ma()
{
int x=,c;
for(int i=;i<=len;i++)
{
c=idx(str[i]);
for(;x&&!trs[x][c];x=pre[x]);
if(!x){ma[i]=,x=;continue;}
ma[i]=min(ma[i-]+,dep[x]+);
x=trs[x][c];
}
}
};
int que[N1],f[N1];
int check(int L)
{
int i,j,hd=,tl=;
que[++tl]=;
for(i=;i<L;i++) f[i]=;
for(i=max(,L);i<=len;i++)
{
j=i-L;
while(hd<=tl&&f[que[tl]]-que[tl]<=f[j]-j) tl--;
que[++tl]=j;
while(hd<=tl&&que[hd]<i-ma[i]) hd++;
if(hd>tl) f[i]=f[i-];
else f[i]=max(f[i-],f[que[hd]]+i-que[hd]);
}
if(*f[len]>=*len) return ;
else return ;
} int main()
{
scanf("%d%d",&N,&M);
int i,j,l,r,n,m,mid,mxl=,ans;
SAM::init();
for(m=;m<=M;m++)
{
scanf("%s",str+);
len=strlen(str+);
mxl=max(mxl,len);
for(i=;i<=len;i++)
SAM::insert(idx(str[i]));
SAM::reduct();
}
for(n=;n<=N;n++)
{
scanf("%s",str+);
len=strlen(str+);
SAM::get_ma();
l=,r=min(len,mxl),ans=;
while(l<=r){
mid=(l+r)>>;
if(check(mid)) ans=mid,l=mid+;
else r=mid-;
}
printf("%d\n",ans);
}
return ;
}
BZOJ 2806 [Ctsc2012]Cheat (后缀自动机+二分+单调队列+dp)的更多相关文章
- bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP
2806: [Ctsc2012]Cheat Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 583 Solved: 330[Submit][Statu ...
- BZOJ 2806 [Ctsc2012]Cheat ——后缀自动机 单调队列优化DP
先建出广义后缀自动机. 然后跑出文章中每一个位置的最大匹配距离. 然后定义$f[i]$表示匹配到以$i$结尾的串时,最长的匹配距离. 显然可以二分$L$的取值. 然后容易得到$DP$方程 $f[i]= ...
- BZOJ2806 [Ctsc2012]Cheat 【后缀自动机 + 二分 + 单调队列优化DP】
题目 输入格式 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库 的行数 接下来M行的01串,表示标准作文库 接下来N行的01串,表示N篇作文 输出格式 N行,每行一个整数,表示这篇作文的 ...
- 【BZOJ2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化DP
[BZOJ2806][Ctsc2012]Cheat Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的 ...
- BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]
2806: [Ctsc2012]Cheat 题意: 多个主串和多个询问串,每次询问将询问串分成多个连续子串,如果一个子串长度>=L且在主串中出现过就是熟悉的 如果熟悉的字符串长度>=询问串 ...
- [bzoj2806][Ctsc2012]Cheat(后缀自动机(SAM)+二分答案+单调队列优化dp)
偷懒直接把bzoj的网页内容ctrlcv过来了 2806: [Ctsc2012]Cheat Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1943 ...
- 【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)
2806: [Ctsc2012]Cheat Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1262 Solved: 643 Description ...
- bzoj 2806 [Ctsc2012]Cheat——广义后缀自动机+单调队列优化DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2806 只想着怎么用后缀数据结构做,其实应该考虑结合其他算法. 可以二分那个长度 L .设当前 ...
- BZOJ.2806.[CTSC2012]Cheat(广义后缀自动机 DP 单调队列)
题目链接 首先二分答案L.然后就是判断能否将原串划分出一些长度不小于L的子串,这些子串要是给定n个串中的某个串的子串,且满足它们的长度之和不小于原串长度的90%. 贪心多长选一段什么的显然不对.老老实 ...
随机推荐
- django与mysql实现简单的增删查改
模型定义 from django.db import models class Grades(models.Model): g_name = models.CharField(max_length=2 ...
- assound.conf
pcm.!dmix {type dmixipc_key 5678293ipc_key_add_uid yesslave {pcm "hw:0,0"period_time 0peri ...
- 小松之LINUX 驱动学习笔记(开篇)
时间对每个人都是公平的,就看你怎么对待他.每天多努力一点,未来就会轻松一点.作为一名北漂,感受着首都的压力,也曾萌生过逃离北上广的想法,但是,最后我最终还是选择留下来,随着年龄的增长,我已经没有那么多 ...
- TensorFlow 制作自己的TFRecord数据集
官网的mnist和cifar10数据之后,笔者尝试着制作自己的数据集,并保存,读入,显示. TensorFlow可以支持cifar10的数据格式, 也提供了标准的TFRecord 格式,而关于 ten ...
- Anaconda安装tensorflow遇到的问题(转)
tensorflow安装教程 1.找不到Anaconda Prompt 其他教程中说AnacondaPrompt在安装的Anaconda文件夹下面(如D:/Anaconda),但是我在安装中没有找到, ...
- C# 日期格式
# DateTime日期格式化 在C#中DateTime是一个包含日期.时间的类型,此类型通过ToString()转换为字符串时,可根据传入给Tostring()的参数转换为多种字符串格式. 目录 1 ...
- C 语言预编译 #if #else
这个方法我一般用来调试的时候用,有时候串口打印信息太多,一条条注释就很麻烦,于是就用这种方法,定义个宏变量,判断宏变量的条件,来达到改变宏变量的值控制那些代码编译,那些不编译的目的,这样就不用一条条代 ...
- ie6下position:fixed定位问题
1. *html{ background-image:url(about:blank); background-attachment:fixed;}2.将需要用固定定位的元素中加上_position: ...
- php常量,提前定义常量,魔术常量及基本数据类型
常量 定义: 形式一 // define("PI",常量值); define("PI",3.14); define("school",&qu ...
- hdu 1166 敌兵布阵——(区间和)树状数组/线段树
pid=1166">here:http://acm.hdu.edu.cn/showproblem.php?pid=1166 Input 第一行一个整数T.表示有T组数据. 每组数据第一 ...