传送门


先将所有模板串扔进广义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. loadrunner 场景设计-设计与实践

    场景设计-设计与实践 by:授客 QQ:1033553122 以lr 11.0 自带Web Tours为例,进行以下测试 说明:以下测试仅供演示,学习设计思路 A.确定系统组件 简单B/S架构:Cli ...

  2. [Linux.NET]Nginx 泛解析配置请求映射到多端口实现二级域名访问

    由于想实现一个域名放置多个应用运行的目的,而不想通过域名后加端口号方式处理,这种方式处理记起来太麻烦,偷懒党简直不能忍,故而考虑了使用二级域名来处理多个应用同时运行.Google了一番资料并进行了尝试 ...

  3. [20171225]没有备份数据文件的恢复.txt

    [20171225]没有备份数据文件的恢复.txt --//别人问的问题,增加了数据文件没有备份,如何恢复,实际上很简单,因为当前控制文件有记录建立时间只要从建立数据文件开始的--//归档日志都存在恢 ...

  4. CSS| 學習心得

    resize :both , 只有overflow設置為auto時, 才能起作用???

  5. IDEA 如何查看一个类里面的所有方法

    快捷键:Alt+7

  6. fedora输入法

    fedora自带输入法,另外如果自己鼓捣的话很可能身心俱疲. 打开设置(在桌面右击也能打开) 区域和语言 在输入源中添加 汉语(中国) 快捷键 输入源切换:win+space 中英文切换:shift

  7. 拓普微智能TFT液晶显示模块

    关键词: 串口屏, 液晶屏, TFT,人机界面 概述: 智能模块(Smart LCD)是专为工业显示应用而设计的TFT液晶显示模块. 模块自带主控IC.Flash存储器.实时嵌入式操作系统,客户主机可 ...

  8. 简单规划dp sumsets

    Farmer John commanded his cows to search for different sets of numbers that sum to a given number. T ...

  9. bzoj5093:[Lydsy1711月赛]图的价值

    题目 首先考虑到这是一张有标号的图,每一个点的地位是相等的,因此我们只需要求出一个点的价值和乘上\(n\)就好了 考虑一个点有多少种情况下度数为\(i\) 显然我们可以让除了这个点的剩下的\(n-1\ ...

  10. Python--Windows下安装虚拟环境

    为什么需要虚拟环境 在python开发中,我们可能会遇到一种情况:就是当前的项目依赖的是某一个版本,但是另一个项目依赖的是另一个版本,这样就会造成依赖冲突.在这种情况之下,我们就需要一个工具能够将这两 ...