【bzoj2806】 Ctsc2012—Cheat

http://www.lydsy.com/JudgeOnline/problem.php?id=2806 (题目链接)

题意

  给出M个字符串组成“标准库”。定义L表示将一个字符串分成若干段,每一段的长度不小于L,其中是在标准库中任一字符串的子串的字符“段”的长度之和不小于原字符串长度之和的90%。N个询问,每个给出一个字符串,求其满足条件的最大的L。

Solution

  对于每一个询问,我们在线做,话说离线怎么做,整体二分吗→_→

  很显然,这应该是要二分答案,考虑怎么check。我们想到了dp:${f_i}$表示后缀${i}$的最长覆盖长度。

$${f_{i}=Max\{f_{i+1},f_j+j-i\},i+L_0<=j<=R_i+i}$$

  其中${L_0}$表示当前二分的答案,${R_i}$表示从第${i}$位开始能够匹配到的最长的连续段长度。注意这个要倒着做→_→

  然而这个dp是${O(n^2)}$的,我们还需要优化,加上一个括号:

$${f_i=Max\{f_{i+1},(f_j+j)-i\},i+L_0<=j<=R_i+i}$$

  于是${f_j+j}$就只与${j}$有关了,我们考虑单调队列。如果队首因为它的位置${>=R_i+i}$而被踢出了队列,那么它必然不会因为后面串的${R_i}$长度增大而被加回来,因为每往后面挪一格长度只可能+1,然后又因为i会-1,所以就是不变的。

  那么我们就可以${O(nlogn)}$的求解每一个询问了。

  那么只剩下一个问题,${R_i}$怎么求。考虑后缀数组。将所有串接在一起,求一个后缀数组,然后求出height,那么如果一个后缀是询问串的后缀,与其最近的“标准库”中的后缀的height就是它的${R_i}$。然后倍增构后缀数组就TLE飞了→_→,等下补一发后缀自动机的。

  UPD 2017.1.19:

  这几天一直在考试,拖到了现在。原来就是把“标准库”中的串用分隔符接起来构后缀自动机,之后每一个询问串在上面跑匹配就可以轻松的求出${R_i}$了,我还写了发后缀自动机构后缀数组,然而分隔符太大了,开不下→_→。

  因为之前的dp是倒着求的,所以这里的后缀自动机和匹配都是倒着来的→_→,懒得再去改dp和二分答案了。。

细节

  构造后缀数组时桶的大小要注意;求${R_i}$的时候要想清楚→_→。

  后缀自动机匹配的时候长度要随着匹配失败跳parent树的移动而改变。

代码(后缀数组)

// bzoj2806
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<ctime>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;const int maxn=2000010;
int f[maxn],S[maxn],a[maxn],vis[maxn],q[maxn],pl[maxn],pr[maxn],R[maxn];
int rank[maxn],sa[maxn],height[maxn];
char s[maxn];
int n,m,ans;namespace Suffix {int wa[maxn],wb[maxn],ww[maxn];bool cmp(int *r,int a,int b,int l) {return r[a]==r[b] && r[a+l]==r[b+l];}void da(int *r,int *sa,int n,int m) {int i,j,p,*x=wa,*y=wb;for (i=0;i<=m;i++) ww[i]=0;for (i=1;i<=n;i++) ww[x[i]=r[i]]++;for (i=1;i<=m;i++) ww[i]+=ww[i-1];for (i=n;i>=1;i--) sa[ww[x[i]]--]=i;for (p=0,j=1;p<n;j*=2,m=p) {for (p=0,i=n-j+1;i<=n;i++) y[++p]=i;for (i=1;i<=n;i++) if (sa[i]>j) y[++p]=sa[i]-j;for (i=0;i<=m;i++) ww[i]=0;for (i=1;i<=n;i++) ww[x[y[i]]]++;for (i=1;i<=m;i++) ww[i]+=ww[i-1];for (i=n;i>=1;i--) sa[ww[x[y[i]]]--]=y[i];for (swap(x,y),p=x[sa[1]]=1,i=2;i<=n;i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j) ? p : ++p;}}void calheight(int *r,int *sa,int n) {for (int i=1;i<=n;i++) rank[sa[i]]=i;for (int k=0,i=1;i<=n;i++) {if (k) k--;int j=sa[rank[i]-1];while (r[i+k]==r[j+k]) k++;height[rank[i]]=k;}}
}
using namespace Suffix;bool dp(int x,int L0) {for (int i=pl[x];i<=pr[x];i++) f[i]=0;int l=1,r=1;q[1]=pr[x]+1;for (int i=pr[x]-L0+1;i>=pl[x];i--) {while (l<=r && q[l]>i+R[i]) l++;f[i]=f[i+1];if (l<=r) f[i]=max(f[i],f[q[l]]+q[l]-i);if (i+L0-1<=pr[x]) {while (l<=r && f[q[r]]+q[r]<f[i+L0-1]+i+L0-1) r--;q[++r]=i+L0-1;}}return 10*f[pl[x]]>=(pr[x]-pl[x]+1)*9;
}
int main() {scanf("%d%d",&n,&m);int len=0;S[0]=inf;for (int i=1;i<=m;i++) {scanf("%s",s+1);for (int j=1;j<=strlen(s+1);j++) S[++len]=s[j]-'0';S[++len]=i+2;}for (int i=1;i<=n;i++) {scanf("%s",s+1);int tmp=strlen(s+1);pl[i]=len+1;for (int j=1;j<=tmp;j++) S[++len]=s[j]-'0',vis[len]=1;pr[i]=len;S[++len]=i+m+2;}da(S,sa,len,1000000);calheight(S,sa,len);for (int l=inf,i=2;i<=len;i++) {if (i==2) while (vis[sa[i-1]] && vis[sa[i]] && i<=len) i++;if (!vis[sa[i]]) l=inf;else {l=min(l,height[i]);R[sa[i]]=max(R[sa[i]],l);}}for (int l=inf,i=len-1;i>=1;i--) {if (i==len-1) while (vis[sa[i+1]] && vis[sa[i]] && i>=1) i--;if (!vis[sa[i]]) l=inf;else {l=min(l,height[i+1]);R[sa[i]]=max(R[sa[i]],l);}}for (int i=1;i<=n;i++) {int l=0,r=pr[i]-pl[i]+1,ans=0;while (l<=r) {int mid=(l+r)>>1;if (dp(i,mid)) ans=mid,l=mid+1;else r=mid-1;}printf("%d\n",ans);}return 0;
}

 代码(后缀自动机)

// bzoj2806
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
#include<ctime>
#define LL long long
#define inf 1<<30
#define Pi acos(-1.0)
#define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
using namespace std;const int maxn=2000010;
int f[maxn],q[maxn],R[maxn];
char s[maxn];
int n,m,N,ans;namespace SAM {int par[maxn<<1],len[maxn<<1],pos[maxn<<1],ch[maxn>>1][10];int last,Dargen,sz;void Extend(int c) {int np=++sz,p=last;last=np;len[np]=len[p]+1;for (;p && !ch[p][c];p=par[p]) ch[p][c]=np;if (!p) par[np]=Dargen;else {int q=ch[p][c];if (len[p]+1==len[q]) par[np]=q;else {int nq=++sz;len[nq]=len[p]+1;memcpy(ch[nq],ch[q],sizeof(ch[q]));par[nq]=par[q];par[np]=par[q]=nq;for (;p && ch[p][c]==q;p=par[p]) ch[p][c]=nq;}}}void match() {int ll=0;for (int p=Dargen,i=n;i>=1;i--) {while (p>1 && !ch[p][s[i]-'0']) p=par[p],ll=len[p];if (ch[p][s[i]-'0']) p=ch[p][s[i]-'0'],ll++;else ll=0;R[i]=ll;}}
}
using namespace SAM;bool dp(int x,int L0) {for (int i=1;i<=n+1;i++) f[i]=0;int l=1,r=1;q[1]=n+1;for (int i=n-L0+1;i>=1;i--) {while (l<=r && q[l]>i+R[i]) l++;f[i]=f[i+1];if (l<=r) f[i]=max(f[i],f[q[l]]+q[l]-i);if (i+L0-1<=n) {while (l<=r && f[q[r]]+q[r]<f[i+L0-1]+i+L0-1) r--;q[++r]=i+L0-1;}}return 10*f[1]>=n*9;
}
int main() {scanf("%d%d",&N,&m);SAM::sz=SAM::Dargen=SAM::last=1;for (int i=1;i<=m;i++) {scanf("%s",s+1);for (int i=strlen(s+1);i>=1;i--) Extend(s[i]-'0');Extend(2);}for (int i=1;i<=N;i++) {scanf("%s",s+1);n=strlen(s+1);match();int l=0,r=n,ans=0;while (l<=r) {int mid=(l+r)>>1;if (dp(i,mid)) ans=mid,l=mid+1;else r=mid-1;}printf("%d\n",ans);}return 0;
}

 

转载于:https://www.cnblogs.com/MashiroSky/p/6294884.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/469552.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

怎样在Linux驱动中创建proc节点(示例)

一、定义proc节点的读、写函数 static int tp_switch_writeproc(struct file *file,const char *buffer, unsigned long count,void *data) { sscanf(buffer,"%d", &tp_dbg); printk("tpd: proc-->tp_dbg %d\n", tp_dbg); return count; } static …

数据结构之二叉树:二叉查找树的先序、中序、后序、层序遍历,Python代码实现——10(续)

数据结构之二叉查找树的代码实现 本节继续对上一节BST的功能实现 在实现之前&#xff0c;先对要实现的功能进行一下简单的介绍 BST的几种常见遍历方式 以一个简化的树为例&#xff0c;一棵树包含根(父)结点和其左子树及右子树&#xff1a; 遍历顺序的先后是指根(父)结点被遍…

OpenCV_04 几何变换:图像缩放+图像平移+图像旋转+仿射变换+透射变换+图像金字塔

1 图像缩放 缩放是对图像的大小进行调整&#xff0c;即使图像放大或缩小。 API cv2.resize(src,dsize,fx0,fy0,interpolationcv2.INTER_LINEAR)参数&#xff1a; src : 输入图像 dsize: 绝对尺寸&#xff0c;直接指定调整后图像的大小 fx,fy: 相对尺寸&#xff0c;将dsize设…

Direct2D教程(九)渲染位图

概述 这篇的标题更确切的说应该叫位图画刷&#xff0c;这样才好和前几篇对应起来。在Direct2D中&#xff0c;位图的渲染也是通过画刷来实现的。 Direct2D中并没有直接操作位图的接口&#xff0c;而是借助WIC&#xff08;Windows Image Component&#xff09;来完成的。今天我们…

OpenCV_05 形态学操作:连通性+腐蚀和膨胀+开闭运算+礼帽和黑帽

1 连通性 在图像中&#xff0c;最小的单位是像素&#xff0c;每个像素周围有8个邻接像素&#xff0c;常见的邻接关系有3种&#xff1a;4邻接、8邻接和D邻接。分别如下图所示&#xff1a; 4邻接&#xff1a;像素p(x,y)的4邻域是&#xff1a;(x1,y)&#xff1b;(x-1,y)&#xff…

数据结构之二叉树:折纸问题——11

数据结构之二叉树&#xff1a;Python代码解决折纸问题 折纸问题 要求&#xff1a;请把一段纸条竖着放在桌子上&#xff0c;然后从纸条的下边向上方对折1次&#xff0c;压出折痕后展开。此时折痕是凹下去的&#xff0c;即折痕突起的方向指向纸条的背面。如果从纸条的下边向上方…

OpenCV_06 图像平滑:图像噪声+图像平滑+滤波

1 图像噪声 由于图像采集、处理、传输等过程不可避免的会受到噪声的污染&#xff0c;妨碍人们对图像理解及分析处理。常见的图像噪声有高斯噪声、椒盐噪声等。 1.1 椒盐噪声 椒盐噪声也称为脉冲噪声&#xff0c;是图像中经常见到的一种噪声&#xff0c;它是一种随机出现的白…

Android kernel Crash后,定位出错点的方法

1. 将/prebuild/gcc/linux-x86/arm/arm-linux-androideabi-4.6/bin/arm-linux-androideabi-gdb 拷贝到/usr/local/bin下 2. 进入out/target/product/工程名xxx/obj/KERNEL_OBJ 目录,找到文件vmlinux

Vuejs 写法实例

原文地址&#xff1a;http://www.jianshu.com/p/293387d240b2 Hello World <div id"app">{{ message }}<button v-on:click"clickMe()">点击</button> <button v-on:click"clickMe">无参数的简写</button> </d…

数据结构之堆:堆的介绍与python实现——12

堆的简单实现与代码实现 堆的定义 在定义堆&#xff08;heap&#xff09;之前&#xff0c;先回顾一下完全二叉树的定义&#xff1a; 完全二叉树&#xff1a;除了最后一层的结点有可能没有达到最大值外&#xff0c;其它层的结点值都达到最大值&#xff0c;此外最后一层的叶子…

OpenCV_07 直方图:灰度直方图+直方图均衡化

1 灰度直方图 1.1 原理 直方图是对数据进行统计的一种方法&#xff0c;并且将统计值组织到一系列实现定义好的 bin 当中。其中&#xff0c; bin 为直方图中经常用到的一个概念&#xff0c;可以译为 “直条” 或 “组距”&#xff0c;其数值是从数据中计算出的特征统计量&…

OpenCV_08 边缘检测:Sobel检测算子+Laplacian算子+Canny边缘检测

1 原理 边缘检测是图像处理和计算机视觉中的基本问题&#xff0c;边缘检测的目的是标识数字图像中亮度变化明显的点。图像属性中的显著变化通常反映了属性的重要事件和变化。边缘的表现形式如下图所示&#xff1a; 图像边缘检测大幅度地减少了数据量&#xff0c;并且剔除了可以…

linux module_init

就像你写C程序需要包含C库的头文件那样&#xff0c;Linux内核编程也需要包含Kernel头文件&#xff0c;大多的Linux驱动程序需要包含下面三个头文件&#xff1a; #include <linux/init.h> #include <linux/module.h> #include <linux/kernel.h> 其中&#xff…

数据结构之堆:堆的排序,Python代码实现——13

堆的排序&#xff0c;使用Python代码实现 上一节对堆进行了简单的实现&#xff0c;但是实现的堆只是部分有序&#xff08;父结点大于子结点&#xff0c;子结点之间无序&#xff09; 接下来我们实现对堆的所有元素进行升序排序 排序过程 实现步骤: 构造堆;得到堆顶元素,这个…

Anaconda 镜像源操作(查看配置删除)

一、Anaconda查看镜像配置 conda config --show channelschannels: https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/defaults二、添加清华大学镜像 conda config --add channels https://mirrors.tuna.t…

multi-line comment In file

写注释引起的编译问题&#xff1a; //s3c_gpio_cfgpin(pin, GTP_INT_CFG); \//s3c_gpio_cfgpin(pin, GTP_INT_CFG); \ 如果向上面那样写注释的话&#xff0c;就会引起问题&#xff0c;GCC&#xff0c;警告&#xff0c;有可能编译不通过&#xff0c;我遇到的问题就是编译不通过…

资治通鉴

本书于2017年1月15日开始看并于2017年1月17日看完&#xff0c;基本上只是culver看了一遍&#xff0c;只了解了故事而并没有分析&#xff0c;故事中每个人的思想和可能的想法&#xff0c;而且司马光对于宋朝以前的历史是截取了很多的片段记载的&#xff0c;并不能完整的了解历史…

【完美解决方案】module ‘cv2.cv2‘ has no attribute ‘xfeatures2d‘

一、问题描述 在学习openCV的过程中使用了SIFT的时候&#xff0c;发现书上的代码用不了&#xff0c;报错&#xff1a; module cv2.cv2 has no attribute xfeatures2d 二、问题原因 算法被申请了专利&#xff0c;将opencv版本退到3.4.2即可解决&#xff0c;必须小于等于Python…

数据结构之优先队列:优先队列的介绍与基础操作实现,Python代码实现——14

优先队列(Priority queue)的介绍 优先队列是计算机中一种抽象的数据结构类&#xff0c;它有着一个类似和队列或者堆的结构&#xff0c;但是其中每个元素额外有一个优先级别在一个优先队列中&#xff0c;一个高优先顺序的元素会先执行与低优先顺序的元素。在它的执行过程中&…

初识--百年孤独

转载于:https://www.cnblogs.com/xmyun/articles/6306290.html