bzoj

luogu

题目描述

阿米巴是小强的好朋友。

在小强眼中,阿米巴是一个作文成绩很高的文艺青年。为了获取考试作文的真谛,小强向阿米巴求教。阿米巴给小强展示了几篇作文,小强觉得这些文章怎么看怎么觉得熟悉,仿佛是某些范文拼拼凑凑而成的。小强不禁向阿米巴投去了疑惑的眼光,却发现阿米巴露出了一个狡黠的微笑。

为了有说服力地向阿米巴展示阿米巴的作文是多么让人觉得“眼熟”,小强想出了一个评定作文 “熟悉程度”的量化指标\(L_0\).小强首先将作文转化成一个01串。之后,小强搜集了各路名家的文章,同样分别转化成01串后,整理出一个包含了\(M\)个01串的“ 标准作文库 ”。

小强认为:如果一个01串长度不少于\(L\)且在“标准作文库”中的某个串里出现过(即,它是“标准作文库”的某个串的一个连续子串),那么它是“熟悉”的。对于一篇作文(一个01串)\(A\),如果能够把\(A\)分割成若干段子串,其中“ 熟悉 ”的子串的 长度总和不少于\(A\)总长度的\(90%\),那么称\(A\)是 “ 熟悉的文章 ”。\(L_0\)是 能够让\(A\)成为“熟悉的文章”的所有\(L\)的最大值(如果不存在这样的\(L\),那么规定 \(L_0=0\))。

举个例子:

小强的作文库里包含了如下\(2\)个字符串:

10110

000001110

有一篇待考察的作文是:

1011001100

小强计算出这篇作文\(L\)的最大值是\(4\),因为待考察的作文可以视作'10110'+'0110'+'0',其中'10110'和'0110'被判定为“熟悉”的。而当\(L=5\)或是更大的时候,不存在符合题意的分割方法。所以,这篇作文的\(L_0=4\)。小强认为阿米巴作文的\(L_0\)值比其他同学的明显要大。请你帮他验证一下。

sol

显然\(L_0\)是可二分的吧。

那么我们二分出一个\(L\),对原序列做一遍\(check\)

发现这个玩意儿很像一个序列\(dp\)?

设\(f_i\)表示前\(i\)个位置能够匹配的最大长度。那么转移有:

\[f_i=max(f_j+i-j),i-j>=L且s[j+1..i]能够匹配
\]

这个是强制\(i\)在匹配里的,那么令\(f[i]=max(f[i],f[i-1])\)就可以满足设定了。

我们设\(pp[i]\)表示匹配到\(i\)位置时的最长匹配长度,那么\(s[j+1..i]\)能够匹配就当且仅当\(j>=i-pp[i]\)。显然\(i-pp[i]\)是单调的,所以我们可以维护一个\(i\)递增\(f[i]-i\)递减的单调队列,每次取队首元素更新\(dp\)值。

至于\(i-j>=L\)的限制,我们只要在计算\(f[i]\)之前,把\(i-L\)插入到单调队列里面去就行了。

复杂度变成了优秀的\(O(n\log{n})\)

code

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 2e6+5;
int n,m,l,last=1,tot=1,tr[N][2],fa[N],len[N],pp[N],q[N],dp[N];
char s[N];
void extend(int c)
{
int v=last,u=++tot;last=u;
len[u]=len[v]+1;
while (v&&!tr[v][c]) tr[v][c]=u,v=fa[v];
if (!v) fa[u]=1;
else{
int x=tr[v][c];
if (len[x]==len[v]+1) fa[u]=x;
else{
int y=++tot;
memcpy(tr[y],tr[x],sizeof(tr[y]));
fa[y]=fa[x];fa[x]=fa[u]=y;len[y]=len[v]+1;
while (v&&tr[v][c]==x) tr[v][c]=y,v=fa[v];
}
}
}
bool check(int mid)
{
int hd=1,tl=0;
for (int i=1;i<=l;++i)
{
dp[i]=dp[i-1];
if (i<mid) continue;
while (hd<=tl&&dp[q[tl]]-q[tl]<=dp[i-mid]-i+mid) --tl;
q[++tl]=i-mid;
while (hd<=tl&&q[hd]<i-pp[i]) ++hd;
if (hd<=tl) dp[i]=max(dp[i],dp[q[hd]]+i-q[hd]);
}
return dp[l]*10>=l*9;
}
int main()
{
scanf("%d%d",&n,&m);
while (m--)
{
scanf("%s",s+1);l=strlen(s+1);
last=1;
for (int i=1;i<=l;++i) extend(s[i]-'0');
}
while (n--)
{
scanf("%s",s+1);l=strlen(s+1);
for (int i=1,now=1,cnt=0;i<=l;++i)
{
int c=s[i]-'0';
if (tr[now][c]) ++cnt,now=tr[now][c];
else{
while (now&&!tr[now][c]) now=fa[now];
if (!now) cnt=0,now=1;
else cnt=len[now]+1,now=tr[now][c];
}
pp[i]=cnt;
}
int L=0,R=l;
while (L<R)
{
int mid=L+R+1>>1;
if (check(mid)) L=mid;
else R=mid-1;
}
printf("%d\n",L);
}
return 0;
}

[BZOJ2806][CTSC2012]熟悉的文章(Cheat)的更多相关文章

  1. P4022 [CTSC2012]熟悉的文章

    题目 P4022 [CTSC2012]熟悉的文章 题目大意:多个文本串,多个匹配串,我们求\(L\),\(L\)指(匹配串中\(≥L\)长度的子串出现在文本串才为"熟悉",使得匹配 ...

  2. [CTSC2012]熟悉的文章(后缀自动机+动态规划)

    题目描述 阿米巴是小强的好朋友. 在小强眼中,阿米巴是一个作文成绩很高的文艺青年.为了获取考试作文的真谛,小强向阿米巴求教.阿米巴给小强展示了几篇作文,小强觉得这些文章怎么看怎么觉得熟悉,仿佛是某些范 ...

  3. 【[CTSC2012]熟悉的文章】

    题目 好题啊 \(SAM\)+单调队列优化\(dp\) 首先这个\(L\)满足单调性真是非常显然我们可以直接二分 二分之后套一个\(dp\)就好了 设\(dp[i]\)表示到达\(i\)位置熟悉的文章 ...

  4. 题解-CTSC2012 熟悉的文章

    Problem bzoj 题目大意:给定多个标准串和一个文本串,全部为01串,如果一个串长度不少于\(L\)且是任意一个标准串的子串,那么它是"熟悉"的.对于文本串\(A\),把\ ...

  5. CTSC2012 熟悉的文章

    传送门 首先很容易想到对于所有的模式串建出广义后缀自动机,之后对于我们每一个要检查的文本串,先在SAM上跑,计算出来每一个位置能匹配到的最远的位置是多少.(就是当前点减去匹配长度) 之后--考虑DP- ...

  6. Luogu4022 CTSC2012 熟悉的文章 广义SAM、二分答案、单调队列

    传送门 先将所有模板串扔进广义SAM.发现作文的\(L0\)具有单调性,即\(L0\)更小不会影响答案,所以二分答案. 假设当前二分的值为\(mid\),将当前的作文放到广义SAM上匹配. 设对于第\ ...

  7. [CTSC2012]熟悉的文章 (后缀自动机 单调队列)

    /* 首先答案显然是具有单调性的, 所以可以二分进行判断 然后当我们二分过后考虑dp来求最长匹配个数, 发现每个点能够转移的地点 肯定是一段区间, 然后这样就能够得到一个log^2算法 至于每个点的匹 ...

  8. [CTSC2012]熟悉的文章 后缀自动机

    题面:洛谷 题解: 观察到L是可二分的,因此我们二分L,然后就只需要想办法判断这个L是否可行即可. 因为要尽量使L可行,因此我们需要求出对于给定L,这个串最多能匹配上多少字符. 如果我们可以对每个位置 ...

  9. Luogu-4022 [CTSC2012]熟悉的文章

    广义后缀自动机+DP 对于作文库建出广义后缀自动机,广义自动机就是在每次添加一个字符串之前把\(last=0\),然后正常添加就好了 对于每个询问串,预处理出每个位置\(i\)能向前匹配的最长长度\( ...

随机推荐

  1. 第8章 Foundation Kit介绍

    本文转载至  http://blog.csdn.net/mouyong/article/details/16947321 Objective-C是一门非常精巧实用的语言,目前我们还没有研究完它提供的全 ...

  2. C++ 错误积累

    错误一 VS2012错误:不能在成员函数  的类外部重新声明该函数 解决:检查函数的大括号匹配

  3. EasyNVR流媒体直播之:零基础实现摄像头的全平台直播 (二)公网直播的实现

    接上回(https://blog.csdn.net/xiejiashu/article/details/81276870),我们实现内网直播,可以实现直播的web观看,该篇博文我们将实现公网的直播. ...

  4. 在C语言中使用syslog打印日志到日志文件

    参见 <unix 环境高级编程>第13 章 精灵进程 Syslog为每个事件赋予几个不同的优先级: LOG_EMERG——紧急情况 LOG_ALERT——应该被立即改正的问题,如系统数据库 ...

  5. python利用wxpy监控微信公众号

    此次利用wxpy可以进行微信公众号的消息推送监测(代码超级简单),这样能进行实时获取链接.但是不光会抓到公众号的消息,好友的消息也会抓到(以后会完善的,毕竟现在能用了,而且做项目的微信号肯定是没有好友 ...

  6. 什么是gevent

    gevent是一个基于协程的python网络库,它使用greenlet在libev或libuv事件循环之上提供高级同步API 功能包括 基于libev或libuv的快速时间循环 基于greenlets ...

  7. PAT 天梯赛 L3-001. 凑零钱 【DP】【DFS】

    题目链接 https://www.patest.cn/contests/gplt/L3-001 思路 DP[I][J] I 表示第几个物品 J 表示多少钱 dp[i][j] 为 bool 值 表示 当 ...

  8. Data Structure Binary Tree: Inorder Tree Traversal without Recursion

    http://www.geeksforgeeks.org/inorder-tree-traversal-without-recursion/ #include <iostream> #in ...

  9. python中的id

    python对象都有三个特性分别是身份.类型.值,身份指该对象内存地址,内建函数id()可获得身份,类似于指针的地址,但不能控制这个值,类型决定对象可以保存什么类型的值,值是对象表示的数据项,pyth ...

  10. Python问题解决记录

    Python如何进行中文注释:网址 解决Python UnicodeEncodeError: 'ascii' codec can't encode: 网址1.网址2.网址3 Python 字符串转换为 ...