传送门


先将所有模板串扔进广义SAM。发现作文的\(L0\)具有单调性,即\(L0\)更小不会影响答案,所以二分答案。

假设当前二分的值为\(mid\),将当前的作文放到广义SAM上匹配。

设对于第\(1-i\)个字符来说,最少的失配字符数为\(dp_i\),那么\(dp_i = dp_{i-1} + 1\),且如果当前匹配长度\(len \geq mid\),还有转移\(dp_i = \min\limits_{j=i-len}^{i-mid} dp_j\)。发现在\(i\)增大的过程中\(i-len\)单调不减,因为\(i\)增大\(1\),\(len\)也最多增大\(1\)。这类似于滑动窗口问题,可以单调队列优化转移,做到复杂度\(O(LlogL)\)。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cctype>
#include<algorithm>
#include<cstring>
#include<iomanip>
#include<queue>
//This code is written by Itst
using namespace std; const int MAXN = 2.2e6 + 7;
namespace SAM{
int Lst[MAXN] , Sst[MAXN] , fa[MAXN] , trans[MAXN][2];
int cnt = 1 , L; int insert(int p , int len , int x){
int t = ++cnt;
Lst[t] = len;
while(p && !trans[p][x]){
trans[p][x] = t;
p = fa[p];
}
if(!p){
Sst[t] = fa[t] = 1;
return t;
}
int q = trans[p][x];
Sst[t] = Lst[p] + 2;
if(Lst[q] == Lst[p] + 1){
fa[t] = q;
return t;
}
int k = ++cnt;
memcpy(trans[k] , trans[q] , sizeof(trans[k]));
Lst[k] = Lst[p] + 1;
Sst[k] = Sst[q];
Sst[q] = Lst[p] + 2;
fa[k] = fa[q];
fa[q] = fa[t] = k;
while(trans[p][x] == q){
trans[p][x] = k;
p = fa[p];
}
return t;
}
};
char s[MAXN >> 1];
int ch[MAXN >> 1][2] , dep[MAXN >> 1] , ind[MAXN >> 1];
int N , M , L , cnt = 1; void insert(){
scanf("%s" , s + 1);
L = strlen(s + 1);
int cur = 1;
for(int i = 1 ; i <= L ; ++i){
if(!ch[cur][s[i] - '0']){
ch[cur][s[i] - '0'] = ++cnt;
dep[cnt] = dep[cur] + 1;
}
cur = ch[cur][s[i] - '0'];
}
} void build(){
queue < int > q;
q.push(ind[1] = 1);
while(!q.empty()){
int x = q.front();
q.pop();
for(int i = 0 ; i < 2 ; ++i)
if(ch[x][i]){
ind[ch[x][i]] = SAM::insert(ind[x] , dep[ch[x][i]] , i);
q.push(ch[x][i]);
}
}
} deque < int > q;
int dp[MAXN >> 1];
bool check(int mid){
q.clear();
int u = 1 , len = 0;
for(int i = 1 ; i <= L ; ++i){
dp[i] = dp[i - 1] + 1;
if(SAM::trans[u][s[i] - '0']){
u = SAM::trans[u][s[i] - '0'];
++len;
}
else{
while(u && !SAM::trans[u][s[i] - '0'])
u = SAM::fa[u];
!u ? (u = 1 , len = 0) : (len = SAM::Lst[u] + 1 , u = SAM::trans[u][s[i] - '0']);
}
while(!q.empty() && q.front() < i - len)
q.pop_front();
if(len >= mid){
while(!q.empty() && dp[q.back()] >= dp[i - mid])
q.pop_back();
q.push_back(i - mid);
}
if(!q.empty())
dp[i] = min(dp[i] , dp[q.front()]);
}
return dp[L] <= 0.1 * L;
} int main(){
#ifndef ONLINE_JUDGE
freopen("in" , "r" , stdin);
//freopen("out" , "w" , stdout);
#endif
cin >> N >> M;
for(int i = 1 ; i <= M ; ++i)
insert();
build();
for(int i = 1 ; i <= N ; ++i){
scanf("%s" , s + 1);
L = strlen(s + 1);
int l = 0 , r = L;
while(l < r){
int mid = (l + r + 1) >> 1;
check(mid) ? l = mid : r = mid - 1;
}
cout << l << endl;
}
return 0;
}

Luogu4022 CTSC2012 熟悉的文章 广义SAM、二分答案、单调队列的更多相关文章

  1. CTSC2012 熟悉的文章 广义后缀自动机_单调队列

    没啥难的,主要是单调队列忘了咋求了QAQ... Code: #include <cstdio> #include <algorithm> #include <cstrin ...

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

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

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

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

  4. BZOJ_3316_JC loves Mkk_ 二分答案 + 单调队列

    BZOJ_3316_JC loves Mkk_ 二分答案 + 单调队列 题意: 分析: 拆成链,二分答案,奇偶两个单调队列维护最大子段和,记录方案. 代码: #include <cstdio&g ...

  5. Luogu4022 CTSC2012熟悉的文章(广义后缀自动机+二分答案+动态规划+单调队列)

    对作文库中的串建出广义SAM,然后显然可以二分答案,二分之后考虑暴力dp,设f[i]为前i位最长匹配长度,显然有f[i]=max(f[i-1],f[j]+i-j) (i-j>=l&&am ...

  6. [CTSC2012]熟悉的文章(广义后缀自动机+二分答案+单调队列优化DP)

    我们对作文库建出广义后缀自动机.考虑用\(SAM\)处理出来一个数组\(mx[i]\),表示从作文的第\(i\)个位置向左最远在作文库中出现的子串的长度.这个东西可以在\(SAM\)上跑\(trans ...

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

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

  8. 【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)

    2806: [Ctsc2012]Cheat Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1262  Solved: 643 Description ...

  9. loj 10181 绿色通道 二分答案+单调队列DP

    空题段长度即为单调队列长度区间 每次二分答案进行check即可 #include<bits/stdc++.h> using namespace std; ; const int inf=0 ...

随机推荐

  1. 伪类选择器 E:nth-child(n)、E:nth-of-type(n)

    结构伪类是css3新增的类型选择器. E:nth-child(n).E:nth-of-type(n)就是其中之二.搞懂了这两个,基本上跟他俩一家的其他几个兄弟伙基本上也可以弄懂了. 首先先用文字语言来 ...

  2. SAP MM PIR里的Lower Limit & Upper Limit

    SAP MM PIR里的Lower Limit & Upper Limit 在PIR的价格的detail数据里,有2个字段:Lower Limit和Upper Limit.在今天之前,笔者从未 ...

  3. 导入数据到MongoDB中

    import sys import json import pymongo import datetime from pymongo import MongoClient client = Mongo ...

  4. 活字格Web应用平台学习笔记 8 - 查询记录

    基础教程只剩一点点了,学完算了. 这一课的目标是:查询记录 这个操作的原理很简单,增加一个表格,绑定“部门”那个数据,然后增加一个命令,点击查询. 绑定命令: 完成后的实际界面,查询前面是个下拉框: ...

  5. Ansible--inventory

    简介 Inventory 是 Ansible 管理主机信息的配置文件,相当于系统 HOSTS 文件的功能,默认存放在 /etc/ansible/hosts.为方便批量管理主机,便捷使用其中的主机分组, ...

  6. cmake:善用find_package()提高效率暨查找JNI支持

    cmake提供了很多实用的cmake-modules,通过find_package()命令调用这些modules,用于写CMakeLists.txt脚本时方便的查找依赖的库或其他编译相关的信息,善用这 ...

  7. 三. Redis 主从复制

    特点 1. Master可以拥有多个Slave 2. 多个Slave除可以连接一个Master外,还可以连接多个Salve(避免Master挂掉不能同步,当Master挂掉,其中一个Slave会立即变 ...

  8. uCrop图片裁剪

    uCrop使用 github地址 https://github.com/Yalantis/uCrop然后clone或下载到本地,运行之. 效果预览 app/build.gradle compile ' ...

  9. asp.net根据参数找不到记录后响应404及显示错误页

    在asp.net mvc 中,action方法里根据参数获取数据,假如获取的数据为空,为了响应404错误页,我们可以return HttpNotFound(); 但是在asp.net webform中 ...

  10. 使用EWS API读取邮件

    #安装EwsManagedApi.msi,然后导入EWS模块 Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Ser ...