CTSC2012-Cheat
题意
给出一些母01串,多次询问,每次询问一个01串,问一个最大的\(L\),使得可以在询问串中选出若干个不相交的,长度大于等于\(L\)的子串,这些子串都在母串中出现过,且子串的长度和大于等于询问串总长的\(90\%\) 。
文件大小小于等于1100000字节。
分析
首先如果一个\(L\)可行,那么小于\(L\)的也是可行的,因为是“长度大于等于”。于是我们就二分这个\(L\),转化成判定问题。
把分割序列这类问题可以考虑dp。设\(f_i\)为前\(i\)位能分割出来符合要求的最大子串长度和。显然有:
f_{i-1} \\
f_j+(i-j) && i-j\in [g_i,L]
\end{cases}
\]
第一种情况表示从前一个直接转移过来,即不以\(i\)结尾的。第二种表示以\(i\)结尾的,其中\(g_i\)表示第\(i\)位前面最多可以在母串中匹配多长。这可以通过广义后缀自动机方便地算出来(跳link重置为len,匹配加一)。
显然如果直接暴力dp的话是\(O(n^2)\)的,必须考虑优化。只考虑第二种情况:
f_i=f_j+i-j && i-j\in [g_i,L] \\
f_i=i+(f_j-j) && j\in[i-g_i,i-L]
\end{aligned}
\]
可以注意到,\(i-L\)每次往后移动一格,而\(i-g_i\)的值是单调不减的,因为每次\(i\)加一,\(g_i\)最多加一,即最多多匹配一位,不可能突然多出来匹配的几位,否则就会与前面的\(g\)值矛盾。这就是说,\(j\)的可行区间是单调不减的,所以可以用单调队列优化到\(O(n)\)。队列为队头小,队尾大,每次在队头插入\(i-L\)处的值,如果队头比它小就弹出。在队尾把出了合法区间中的值弹出,取队尾即可。
单次询问的复杂度为\(O(len\log len)\)。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1.1e6+10;
const int maxc=2;
char s[maxn];
int f[maxn],g[maxn],n,que[maxn],ql,qr;
struct SAM {
int t[maxn<<1][maxc],len[maxn<<1],link[maxn<<1],last,tot;
SAM ():tot(1) {}
void reset() {last=1;}
void add(int x) {
if (t[last][x]) {
int p=t[last][x];
if (len[p]==len[last]+1) {
last=p;
return;
} else {
int q=++tot;
len[q]=len[last]+1;
memcpy(t[q],t[p],sizeof t[p]);
for (int j=last;j && t[j][x]==p;j=link[j]) t[j][x]=q;
link[q]=link[p],link[p]=q;
last=q;
return;
}
}
int nw=++tot,i;
len[nw]=len[last]+1;
for (i=last;i && !t[i][x];i=link[i]) t[i][x]=nw;
if (i) {
int p=t[i][x];
if (len[p]==len[i]+1) link[nw]=p; else {
int q=++tot;
len[q]=len[i]+1;
memcpy(t[q],t[p],sizeof t[p]);
for (int j=i;j && t[j][x]==p;j=link[j]) t[j][x]=q;
link[q]=link[p],link[p]=link[nw]=q;
}
} else link[nw]=1;
last=nw;
}
void prepare() {
int now=1,mat=0;
for (int i=1;i<=n;++i) {
int x=s[i]-'0';
while (now!=1 && !t[now][x]) now=link[now],mat=len[now];
if (t[now][x]) now=t[now][x],++mat;
g[i]=mat;
}
}
} sam;
bool dp(int L) {
ql=1,qr=0;
for (int i=L;i<=n;++i) {
f[i]=f[i-1];
while (ql<=qr && f[que[qr]]-que[qr]<f[i-L]-i+L) --qr;
que[++qr]=i-L;
while (ql<=qr && que[ql]<i-g[i]) ++ql;
if (ql<=qr) f[i]=max(f[i],f[que[ql]]+i-que[ql]);
}
return 10*f[n]>=9*n;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("test.in","r",stdin);
#endif
int q,m;
scanf("%d%d",&q,&m);
for (int i=1;i<=m;++i) {
scanf("%s",s+1);
int len=strlen(s+1);
sam.reset();
for (int i=1;i<=len;++i) sam.add(s[i]-'0');
}
while (q--) {
scanf("%s",s+1);
n=strlen(s+1);
memset(g,0,(sizeof g[0])*(n+1));
sam.prepare();
int l=1,r=n,ans;
while (l<=r) {
int mid=(l+r)>>1;
memset(f,0,(sizeof f[0])*(n+1));
if (dp(mid)) ans=mid,l=mid+1; else r=mid-1;
}
printf("%d\n",ans);
}
return 0;
}
CTSC2012-Cheat的更多相关文章
- 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 二分]
2806: [Ctsc2012]Cheat 题意: 多个主串和多个询问串,每次询问将询问串分成多个连续子串,如果一个子串长度>=L且在主串中出现过就是熟悉的 如果熟悉的字符串长度>=询问串 ...
- 【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)
2806: [Ctsc2012]Cheat Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1262 Solved: 643 Description ...
- 【BZOJ2806】[Ctsc2012]Cheat 广义后缀自动机+二分+单调队列优化DP
[BZOJ2806][Ctsc2012]Cheat Description Input 第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库的行数接下来M行的01串,表示标准作文库接下来N行的 ...
- [bzoj2806][Ctsc2012]Cheat(后缀自动机(SAM)+二分答案+单调队列优化dp)
偷懒直接把bzoj的网页内容ctrlcv过来了 2806: [Ctsc2012]Cheat Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1943 ...
- bzoj2806: [Ctsc2012]Cheat(SAM+DP)
2806: [Ctsc2012]Cheat 题目:传送门 题解: 感觉这题考的更多的就是DP啊... 看完题目的第一反应就是广义SAM...(然而并不会) 再YY一会儿想起来可以直接将作文库连成一个母 ...
- bzoj 2806: [Ctsc2012]Cheat
传送门 好久没刷bzoj惹…… 题意不说可以嘛. 首先二分答案. SAM的事情搞完以后就是dp辣. 我们已经对于每个位置i,找到了最小的一个k,使得[k,i]这个子串在模版串中出现过.那么我们需要做的 ...
- bzoj2806 [Ctsc2012]Cheat
我们的目的就是找到一个最大的L0,使得该串的90%可以被分成若干长度>L0的字典串中的子串. 明显可以二分答案,对于二分的每个mid 我们考虑dp:f[i]表示前i个字符,最多能匹配上多少个字符 ...
- bzoj 2806 [Ctsc2012]Cheat——广义后缀自动机+单调队列优化DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2806 只想着怎么用后缀数据结构做,其实应该考虑结合其他算法. 可以二分那个长度 L .设当前 ...
- BZOJ.2806.[CTSC2012]Cheat(广义后缀自动机 DP 单调队列)
题目链接 首先二分答案L.然后就是判断能否将原串划分出一些长度不小于L的子串,这些子串要是给定n个串中的某个串的子串,且满足它们的长度之和不小于原串长度的90%. 贪心多长选一段什么的显然不对.老老实 ...
随机推荐
- tkinter菜单图标,工具栏
所用的图片: import tkinter as tk from tkinter import messagebox, filedialog, simpledialog, colorchooser f ...
- 解决非controller使用,@Autowired或者@Resource注解注入Mapper接口为null的问题
知识点:在service层中注入其它的service接口或者mapper接口都是可以的 但是在封装的Utils工具类中或者非controller普通类中使用@Autowired@Resource注解注 ...
- macOS 10.14 Mojave 开发环境配置Apache多PHP版本
第1部分:macOS 10.14 Mojave Web开发环境 在macOS上开发Web应用程序真是一种乐趣.设置开发环境有很多选择,包括广受欢迎的MAMP Pro,它在Apache,PHP和MySQ ...
- 修改表的字段顺序(mysql)
ALTER TABLE 表名 CHANGE 字段名 字段名 int not null default 1 AFTER 它前面的字段;
- 安装完.net core sdk 后部署 ASP.NET Core 出现错误502.5
将项目升级到和sdk一样的版本 然后 命令行执行 iisreset
- php缩放处理png和jpg图片
本例子介绍使用php自带的GD库对png和jpg图片进行放大和缩小处理 <?php$target_width = 120; //目标图片宽度 $target_height = 150; //目标 ...
- Unity3D之AR开发(二)
上一篇给大家介绍了高通AR的使用,接下来给大家分享一下EasyAR EasyAR引擎简介 EasyAR是做好用的且免费的增强现实(Augmented Reality)引擎,EasyAR为Unity开发 ...
- Lua学习笔记(4): 字符串
Lua的字符串有3种初始化方式 str = "2333" str = 'hahahaha' str = [[ruarua]] 其中单引号和双引号的初始化方式并无区别,[[]]双中括 ...
- 袋鼠云旗下新公司云掣科技启航,深耕云MSP业务助推企业数字化转型
1983年3月15日,国际消费者联盟组织将3月15日确立为国际消费者权益日. 2019年3月15日,袋鼠云举办三周年年会. 一生二,二生三,三生万物.植树节后,万物生长. 年会现场,袋鼠云宣布成立新公 ...
- Pearson Distance
Pearson Distance: where: 1. is the covariance 2. is the standard deviation of 3. is the standard ...