2806: [Ctsc2012]Cheat

Time Limit: 20 Sec  Memory Limit: 256 MB
Submit: 583  Solved: 330
[Submit][Status][Discuss]

Description

Input

第一行两个整数N,M表示待检查的作文数量,和小强的标准作文库
的行数
接下来M行的01串,表示标准作文库
接下来N行的01串,表示N篇作文

Output

N行,每行一个整数,表示这篇作文的Lo 值。

Sample Input

1 2
10110
000001110
1011001100

Sample Output

4

HINT

输入文件不超过1100000字节

注意:题目有改动,可识别的长度不小于90%即可,而不是大于90%

  先将作文库建后缀自动机,多篇文章可以通过在中间加入分隔符来完成。对于每组询问,预处理出每一个位置向前最多匹配多长g[]。

  二分答案len,dp[]表示匹配到当前位置的最多匹配数,对于i位置,dp[i]由一段通过len,与g确定出的区间[l,r]转移,本来用了一个线段树维护,但是由于时间复杂度O(n*log^2n),TLE了,观察发现[l,r]是单调的,故可直接用单调队列。

  网上一半题解过不了数据:1 1 1 1

  另外,对于0.9的问题确实说明了以后能用int就不要用double,实在不行要加eps。

  省选前最后一题了,真觉得时间过得太快了。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 4100000
#define MAXT MAXN*4
#define INF 0x3f3f3f3f
#define lch (now<<1)
#define rch (now<<1^1)
#define smid ((l+r)>>1)
char buf[MAXN];
char *bufnow(buf);
int len[MAXN];
char *str[MAXN];
char buf2[MAXN];
char *bufnow2(buf2);
struct sam_node
{
int nxt[];
int pnt,len;
void Print()
{
for (int i=;i<;i++)
printf("%d[%d] ",i,nxt[i]);
printf("\n");
printf("Pnt:%d\n",pnt);
}
}sam[MAXN];
int tops=;
int last=;
void Add_item(int w)
{
int p=last;
int np=++tops;
sam[np].len=sam[p].len+;
while (p && !sam[p].nxt[w])
sam[p].nxt[w]=np,p=sam[p].pnt;
if (!p)
{
last=np;
sam[np].pnt=;
}else
{
int q=sam[p].nxt[w];
if (sam[p].len+==sam[q].len)
{
sam[np].pnt=q;
}else
{
int nq=++tops;
sam[nq]=sam[q];
sam[nq].len=sam[p].len+;
sam[nq].pnt=sam[q].pnt;
sam[q].pnt=nq;
sam[np].pnt=nq;
while (p && sam[p].nxt[w]==q)
{
sam[p].nxt[w]=nq;
p=sam[p].pnt;
}
}
}
last=np;
}
int g[MAXN];
int dp[MAXN];
int seq[MAXN]; int main()
{
freopen("input.txt","r",stdin);
int n,m;
int x,y;
scanf("%d%d\n",&n,&m);
for (int i=;i<m;i++)
{
scanf("%s\n",bufnow2);
bufnow2+=strlen(bufnow2);
*(bufnow2++)='';
}
for (int i=;i<n;i++)
{
scanf("%s\n",bufnow);
str[i]=bufnow;
bufnow+=len[i]=strlen(bufnow);
bufnow++;
}
for (char *i=buf2;i!=bufnow2;i++)
{
Add_item(*i-'');
}
for (int i=;i<=tops;i++)
{
// printf("SAM<%d>:\n",i);
// sam[i].Print();
}
for (int i=;i<n;i++)
{
int now=;
int clen=;
for (int j=;j<len[i];j++)
{
int w=str[i][j]-'';
if (sam[now].nxt[w])
{
now=sam[now].nxt[w];
clen++;
}else
{
while (now && !sam[now].nxt[w])
now=sam[now].pnt;
if (!now)
{
now=;
clen=;
}else
{
clen=sam[now].len+;
now=sam[now].nxt[w];
}
}
g[j]=clen;
// printf("%d\n",clen);
}
for (int j=len[i];j>=;j--)
g[j]=g[j-];
g[]=;
int l=,r=len[i]+;
int mid;
int head,tail=;
int ny;
while (l+<r)
{
mid=(l+r)>>;
int t;
for (int j=;j<=len[i];j++)
dp[j]=-INF;
dp[]=;
head=,tail=-;
ny=;
for (int j=;j<=len[i];j++)
{
x=j-g[j];
y=j-mid;
while (ny<=y)
{
while (head<=tail && dp[seq[tail]]<=dp[ny])
tail--;
seq[++tail]=ny++;
}
while (head<=tail && seq[head]<x)
head++;
dp[j]=dp[j-]+(j-);
if (head<=tail)
dp[j]=max(dp[j],dp[seq[head]]+j);
dp[j]-=j;
}
t=dp[len[i]]+len[i];
if (t*>=len[i]*)
l=mid;
else
r=mid;
}
printf("%d\n",l);
}
}

bzoj 2806: [Ctsc2012]Cheat 后缀自动机DP的更多相关文章

  1. BZOJ 2806 [Ctsc2012]Cheat ——后缀自动机 单调队列优化DP

    先建出广义后缀自动机. 然后跑出文章中每一个位置的最大匹配距离. 然后定义$f[i]$表示匹配到以$i$结尾的串时,最长的匹配距离. 显然可以二分$L$的取值. 然后容易得到$DP$方程 $f[i]= ...

  2. BZOJ 2806 [Ctsc2012]Cheat (后缀自动机+二分+单调队列+dp)

    题目大意: 给你一堆模式串和文本串 对于每个文本串,我们可以把它不可重叠地拆分成很多子串,如果拆分出的串作为子串出现在了任何一个模式串中,我们称它是“眼熟的”,我们必须保证“眼熟的”子串总长度不小于文 ...

  3. BZOJ 2806: [Ctsc2012]Cheat [广义后缀自动机 单调队列优化DP 二分]

    2806: [Ctsc2012]Cheat 题意: 多个主串和多个询问串,每次询问将询问串分成多个连续子串,如果一个子串长度>=L且在主串中出现过就是熟悉的 如果熟悉的字符串长度>=询问串 ...

  4. [bzoj2806][Ctsc2012]Cheat(后缀自动机(SAM)+二分答案+单调队列优化dp)

    偷懒直接把bzoj的网页内容ctrlcv过来了 2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1943   ...

  5. BZOJ 2806: [Ctsc2012]Cheat(单调队列优化dp+后缀自动机)

    传送门 解题思路 肯定先要建出来广义后缀自动机.刚开始以为是个二分+贪心,写了一下结果\(20\)分.说一下正解,首先显然\(L_0\)具有单调性,是可以二分的.考虑二分后怎样判合法,对于分割序列很容 ...

  6. bzoj 2806 [Ctsc2012]Cheat——广义后缀自动机+单调队列优化DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2806 只想着怎么用后缀数据结构做,其实应该考虑结合其他算法. 可以二分那个长度 L .设当前 ...

  7. BZOJ.2806.[CTSC2012]Cheat(广义后缀自动机 DP 单调队列)

    题目链接 首先二分答案L.然后就是判断能否将原串划分出一些长度不小于L的子串,这些子串要是给定n个串中的某个串的子串,且满足它们的长度之和不小于原串长度的90%. 贪心多长选一段什么的显然不对.老老实 ...

  8. bzoj 2806: [Ctsc2012]Cheat【广义SAM+二分+dp+单调队列】

    把模板串建一个广义SAM 然后在线查询,每次在SAM上预处理出一个a[i]表示i位置向前最多能匹配多长的模板串 二分答案L,dp判断,设f[i]为·~i有几个匹配,转移显然是f[i]=max{f[i- ...

  9. bzoj 2806: [Ctsc2012]Cheat

    传送门 好久没刷bzoj惹…… 题意不说可以嘛. 首先二分答案. SAM的事情搞完以后就是dp辣. 我们已经对于每个位置i,找到了最小的一个k,使得[k,i]这个子串在模版串中出现过.那么我们需要做的 ...

随机推荐

  1. web服务器决定支持多少人同时在线的因素

    经常遇到一些做WEB用户咨询服务器支持在线人数问题,在此做个简单介绍.非技术性讨论,如有疏漏或错误,敬请原谅和指导.以普通单路服务器为例,CPU处理多个进程,并非是同一时刻处理的,(可以精确到1/10 ...

  2. oracle学习----行级锁的理解

    通过实验来理解行级锁的发生 1.创建需要的表 SQL> conn / as sysdba已连接.SQL> create table dept as select * from scott. ...

  3. mysql mac 上启动

    launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.mariadb.plist 中内容: <string>/usr/local/o ...

  4. 需要设置jdk的三处位置:

    需要设置jdk的三处位置:1.tomcat需要一个JDK : Windows--->Preferences--->MyEclipse--->Servers--->Tomcat- ...

  5. 【转】【2015MIIC】迅雷CTO陈磊:互联网思维会害死很多传统企业

    MIIC2015大会的“跨界与重构”论坛上,迅雷CTO.网心科技CEO陈磊的演讲引起众多共鸣——独家揭秘“互联网大忽悠”,给这群人画了像,互联网大忽悠通常有五招: 第1招,画大饼,给你一个宏伟的目标: ...

  6. js 获取当前时间格式怎么转换?

    toLocaleDateString() 得到的时间是 yyyy年MM月dd日 HH:ss:mm 格式的,怎么转换成yyyy-MM-dd HH:ss:mm 在js里面 仅针对这个问题来说,不需要那么大 ...

  7. C#数据类型转换的几种形式

    1.隐式转换:一般是低类型向高类型转化,能够保证值不发生变化. 隐式数值C#数据类型转换: 从 sbyte 到 short.int.long.float.double 或 decimal. 从 byt ...

  8. 百度地图API调用实例之地址标注与位置显示

    之前弄了个谷歌地图API标注的调用实例,后来要求改成百度地图. 感谢主,通过网上资料(百度地图API,百度地图API详解之地图标注)收集及研究, 终于把百度地图标注和显示功能实现出来了,具体实现方法如 ...

  9. exists改写SQL,使其走正确的执行计划

    数据库环境:SQL SERVER 2005 今天看到一条SQL,写得不是很复杂,返回7000多条数据,却执行了15s.SQL文本及各表的数据量如下: SELECT acinv_07.id_item , ...

  10. 伪Base16的构思和实现

    最近看见了一个迅雷地址,发现将其转换为普通链接的工具后,发现所谓专用地址地址就是原地址前加一个表示迅雷的前缀,后进行Base64编码.查阅Base64编码过程后,突发奇想:能否做一个Base16算法? ...