Luogu4022 CTSC2012 熟悉的文章 广义SAM、二分答案、单调队列
先将所有模板串扔进广义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、二分答案、单调队列的更多相关文章
- CTSC2012 熟悉的文章 广义后缀自动机_单调队列
没啥难的,主要是单调队列忘了咋求了QAQ... Code: #include <cstdio> #include <algorithm> #include <cstrin ...
- [bzoj2806][Ctsc2012]Cheat(后缀自动机(SAM)+二分答案+单调队列优化dp)
偷懒直接把bzoj的网页内容ctrlcv过来了 2806: [Ctsc2012]Cheat Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1943 ...
- bzoj 2806: [Ctsc2012]Cheat【广义SAM+二分+dp+单调队列】
把模板串建一个广义SAM 然后在线查询,每次在SAM上预处理出一个a[i]表示i位置向前最多能匹配多长的模板串 二分答案L,dp判断,设f[i]为·~i有几个匹配,转移显然是f[i]=max{f[i- ...
- BZOJ_3316_JC loves Mkk_ 二分答案 + 单调队列
BZOJ_3316_JC loves Mkk_ 二分答案 + 单调队列 题意: 分析: 拆成链,二分答案,奇偶两个单调队列维护最大子段和,记录方案. 代码: #include <cstdio&g ...
- Luogu4022 CTSC2012熟悉的文章(广义后缀自动机+二分答案+动态规划+单调队列)
对作文库中的串建出广义SAM,然后显然可以二分答案,二分之后考虑暴力dp,设f[i]为前i位最长匹配长度,显然有f[i]=max(f[i-1],f[j]+i-j) (i-j>=l&&am ...
- [CTSC2012]熟悉的文章(广义后缀自动机+二分答案+单调队列优化DP)
我们对作文库建出广义后缀自动机.考虑用\(SAM\)处理出来一个数组\(mx[i]\),表示从作文的第\(i\)个位置向左最远在作文库中出现的子串的长度.这个东西可以在\(SAM\)上跑\(trans ...
- Luogu-4022 [CTSC2012]熟悉的文章
广义后缀自动机+DP 对于作文库建出广义后缀自动机,广义自动机就是在每次添加一个字符串之前把\(last=0\),然后正常添加就好了 对于每个询问串,预处理出每个位置\(i\)能向前匹配的最长长度\( ...
- 【BZOJ 2806】 2806: [Ctsc2012]Cheat (SAM+二分+DP+单调队列)
2806: [Ctsc2012]Cheat Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1262 Solved: 643 Description ...
- loj 10181 绿色通道 二分答案+单调队列DP
空题段长度即为单调队列长度区间 每次二分答案进行check即可 #include<bits/stdc++.h> using namespace std; ; const int inf=0 ...
随机推荐
- React 入门学习笔记整理(五)—— state
1.state 1)组件本省也是有状态的,定义在组件内部的state中,state的状态只能由组件自身改变,任何其他组件都不能改变. 当需要改变state时,通过调用setState方法来改变,set ...
- ionic3用极光推送笔记
安卓 环境:ionic3 + 极光 "jpush-phonegap-plugin": "^3.4.3" "cordova-plugin-jcore& ...
- Fiddler抓包使用教程-Https
转载请标明出处:http://blog.csdn.net/zhaoyanjun6/article/details/72956016 本文出自[赵彦军的博客] 开启 Https 抓包 Fiddler 默 ...
- ASP.NET MVC从请求到响应发生了什么
*过程描述 当浏览器发出一个http请求后,该请求被UrlRoutingModule截获,UrlRoutingModule根据请求上下文去系统路由表(RouteTable)中匹配,从中获取一个Rout ...
- VSCode + PYQT5 + QtDesigner 环境搭建和测试
目的:编写Python桌面应用程序. 备注:也可以选择VS2017+QtDesigner ,但更喜欢VSCode 第1步:安装PyQt5和PyQt5-tools pip3 install -i htt ...
- windows7系统最大支持多少内存
目前Windows 7 64位版仅能使用最大为192GB内存. 这是各个版本的具体数据:64位的Windows 7家庭普通版最高可支持8GB内存,家庭高级版最高可支持16GB内存,64位的Win ...
- percona-toolkit大表操作DDL使用
1. 系统与安装数据库 [root@zhang ~]# cat /etc/redhat-release # 也可以使用其他版本 CentOS Linux release (Core) [root@zh ...
- Linux下编辑、编译、调试命令总结——gcc和gdb描述
GCC gcc是linux系统集成的编译器.在linux环境下编辑程序,首先需要克服的便是没有集成开发环境的一键式操作所带来的麻烦.这其中涉及命令行操作.编译选项的设定.文件依赖关系的书写(makef ...
- vue-cli打包到部署到nginx服务器
最近公司把云平台产品用vue 前后端分离的框架来写,前面大部分开发都比较顺利,后面打包部署出了bug 现在记录下自己遇到的哪些坑 1,我直接npm run build 打包出来,打开dist目录下面的 ...
- swift函数的调用约定
The convention of the function, indicated by the attribute. This is similar to the language-level @c ...