题意:给定一个串集合s,每次给定一个串t,询问一个最大的L,使得存在一种划分能把t划分成若干个子串, 其中好的子串总长不小于0.9|t|。好的子串定义为长度不小于L且是s中某一个串的子串。

解:发现这个L可以二分。如果一个L满足那么小一点的L也满足。考虑如何check。

可以求最长的总好的子串长度,然后看是否大于0.9。

这样就能想到DP了。设f[i]表示t[0:i]能划分出的最长好的子串。转移就是考虑第i是否是一个好的子串的结尾。如果是就枚举卡开头,否则就是f[i - 1]。

这个每个位置都有一个最长能匹配的长度mat[i],然后我们以i结尾的好的子串长度限制就是mat[i] ~ mid。

我们发现转移过来的两个限制,右边界显然是每次 + 1的,而左边界单调递增。具体来说,如果i结尾的最长匹配是[k, i],那么i - 1结尾的最长匹配不会比[k, i - 1]还短。

所以用广义SAM搞出来mat,然后二分 + 单调队列优化DP。

注意开头的时候f[0]是mat[0] >= mid。

 #include <bits/stdc++.h>

 const int N = ;
const double eps = 1e-; int tr[N][], fail[N], len[N], tot = ;
int mat[N], f[N];
int stk[N], top, head;
char str[N]; inline int Max(const int &a, const int &b) {
return a > b ? a : b;
} inline int split(int p, int f) {
int Q = tr[p][f], nQ = ++tot;
len[nQ] = len[p] + ;
fail[nQ] = fail[Q];
fail[Q] = nQ;
memcpy(tr[nQ], tr[Q], sizeof(tr[Q]));
while(tr[p][f] == Q) {
tr[p][f] = nQ;
p = fail[p];
}
return nQ;
} inline int insert(int f, int p) {
if(tr[p][f]) {
int Q = tr[p][f];
if(len[Q] == len[p] + ) {
return Q;
}
else {
return split(p, f);
}
}
int np = ++tot;
len[np] = len[p] + ;
while(p && !tr[p][f]) {
tr[p][f] = np;
p = fail[p];
}
if(!p) {
fail[np] = ;
}
else {
int Q = tr[p][f];
if(len[Q] == len[p] + ) {
fail[np] = Q;
}
else {
fail[np] = split(p, f);
}
}
return np;
} int large[N << ];
std::bitset<N * > tag; inline void pushdown(int o) {
if(tag[o]) {
tag.set(o << );
tag.set(o << | );
large[o << ] = large[o << | ] = ;
tag.reset(o);
}
return;
} void change(int p, int v, int l, int r, int o) {
if(l == r) {
tag.reset(o);
large[o] = v;
return;
}
pushdown(o);
int mid = (l + r) >> ;
if(p <= mid) change(p, v, l, mid, o << );
else change(p, v, mid + , r, o << | );
large[o] = Max(large[o << ], large[o << | ]);
return;
} int getMax(int L, int R, int l, int r, int o) {
if(L <= l && r <= R) {
return large[o];
}
int mid = (l + r) >> , ans = ;
pushdown(o);
if(L <= mid) ans = getMax(L, R, l, mid, o << );
if(mid < R) ans = Max(ans, getMax(L, R, mid + , r, o << | ));
return ans;
} int main() {
int n, m;
scanf("%d%d", &n, &m);
for(int i = ; i <= m; i++) {
scanf("%s", str);
int len = strlen(str), last = ;
for(int j = ; j < len; j++) {
last = insert(str[j] - '', last);
}
memset(str, , len * sizeof(char));
} for(int A = ; A <= n; A++) {
scanf("%s", str);
int Len = strlen(str); int p = , lenth = ;
for(int i = ; i < Len; i++) {
int f = str[i] - '';
while(p && !tr[p][f]) {
p = fail[p];
lenth = len[p];
}
if(tr[p][f]) {
p = tr[p][f];
lenth++;
}
else {
p = , lenth = ;
}
mat[i] = lenth;
//printf("mat %d = %d \n", i, mat[i]);
} int l = , r = Len;
while(l < r) {
int mid = (l + r + ) >> ; f[] = (mat[] >= mid); /// ERROR : f[0] = mat[0]
stk[head = top = ] = ;
for(int i = ; i < Len; i++) {
f[i] = f[i - ];
int L = i - mat[i], R = i - mid;
while(head <= top && f[R] - R >= f[stk[top]] - stk[top]) {
--top;
}
stk[++top] = R;
while(head < top && stk[head] < L) {
++head;
}
if(L <= stk[head] && stk[head] <= R) {
f[i] = Max(f[i], f[stk[head]] + i - stk[head]);
}
}
//printf("mid = %d f = %d \n", mid, f[Len - 1]);
if( * f[Len - ] >= * Len) {
l = mid;
}
else {
r = mid - ;
}
}
printf("%d\n", r);
memset(str, , Len * sizeof(char));
} return ;
}

AC代码

我非常傻,一开始写的是个线段树,没看出来单调性...

洛谷P4022 熟悉的文章的更多相关文章

  1. P4022 [CTSC2012]熟悉的文章

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

  2. [洛谷OJ] P1114 “非常男女”计划

    洛谷1114 “非常男女”计划 本题地址:http://www.luogu.org/problem/show?pid=1114 题目描述 近来,初一年的XXX小朋友致力于研究班上同学的配对问题(别想太 ...

  3. 洛谷P2516 [HAOI2010]最长公共子序列(LCS,最短路)

    洛谷题目传送门 一进来就看到一个多月前秒了此题的ysn和YCB%%% 最长公共子序列的\(O(n^2)\)的求解,Dalao们想必都很熟悉了吧!不过蒟蒻突然发现,用网格图貌似可以很轻松地理解这个东东? ...

  4. 洛谷P1516 青蛙的约会(扩展欧几里德)

    洛谷题目传送门 很容易想到,如果他们相遇,他们初始的位置坐标之差\(x-y\)和跳的距离\((n-m)t\)(设\(t\)为跳的次数)之差应该是模纬线长\(l\)同余的,即\((n-m)t\equiv ...

  5. 洛谷 P2317 [HNOI2005]星际贸易 解题报告

    P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...

  6. 洛谷P3348 [ZJOI2016]大森林(LCT,虚点,树上差分)

    洛谷题目传送门 思路分析 最简单粗暴的想法,肯定是大力LCT,每个树都来一遍link之类的操作啦(T飞就不说了) 考虑如何优化算法.如果没有1操作,肯定每个树都长一样.有了1操作,就来仔细分析一下对不 ...

  7. 洛谷 P1045 【麦森数】快速幂

    不用快速幂,压位出奇迹! 本人是个蒟蒻,不太熟悉快速幂,这里给大家介绍一种压位大法. 让我们来分析一下题目,第一位是送分的,有一个专门求位数的函数:n*log10(2)+1. 然后题目中p<=3 ...

  8. 洛谷 P1306 斐波那契公约数

    洛谷 P1306 斐波那契公约数 题目描述 对于Fibonacci数列:1,1,2,3,5,8,13......大家应该很熟悉吧~~~但是现在有一个很“简单”问题:第n项和第m项的最大公约数是多少? ...

  9. 洛谷P1102 A-B数对

    洛谷P1102 A-B数对 https://www.luogu.org/problem/show?pid=1102 题目描述 出题是一件痛苦的事情! 题目看多了也有审美疲劳,于是我舍弃了大家所熟悉的A ...

随机推荐

  1. javaweb中静态文件的处理方法

    方案一:激活Tomcat的defaultServlet来处理静态文件 在web.xml中添加: <servlet-mapping> <servlet-name>default& ...

  2. JS数组 一起组团(什么是数组)一个数组变量可以存放多个数据

    一起组团(什么是数组) 我们知道变量用来存储数据,一个变量只能存储一个内容.假设你想存储10个人的姓名或者存储20个人的数学成绩,就需要10个或20个变量来存储,如果需要存储更多数据,那就会变的更麻烦 ...

  3. linux /bin/find 报错:paths must precede expression 及find应用

    1.问题描述,运行下面的命令,清楚日志 [resin@xx ~]$ ssh xxx  "/usr/bin/find /data/logs/`dirname st_qu/stdout.log` ...

  4. node web项目结构

  5. Ionic3 demo TallyBook 实例1

    1.创建项目 ionic start  TallyBook  blank  创建一个空的项目 ionic cordova  platform  add android   添加andorid平台 io ...

  6. 莫烦PyTorch学习笔记(六)——批处理

    1.要点 Torch 中提供了一种帮你整理你的数据结构的好东西, 叫做 DataLoader, 我们能用它来包装自己的数据, 进行批训练. 而且批训练可以有很多种途径. 2.DataLoader Da ...

  7. 洛谷P5104 红包发红包

    题目链接: P5104 题目分析: 题目和\(n\)是没什么关系的,因为是\(n\)个人抢,其实不一定抢完 其实很显然--就是求一个连续型随机变量的期望 首先设一个随机变量\(X\),表示第一个人拿到 ...

  8. Android基础控件DatePicker的使用

    1.简介 DatePicker日期选择器,自带spinner和calendar两种模式,相关属性: android:calendarTextColor : 日历列表的文本的颜色 android:cal ...

  9. iOS之CAShapeLayer属性简介

    1.CAShapeLayer需要和贝塞尔曲线一块使用! #import <QuartzCore/CALayer.h> NS_ASSUME_NONNULL_BEGIN CA_CLASS_AV ...

  10. 利用R语言制作出漂亮的交互数据可视化

    利用R语言制作出漂亮的交互数据可视化 利用R语言也可以制作出漂亮的交互数据可视化,下面和大家分享一些常用的交互可视化的R包. rCharts包 说起R语言的交互包,第一个想到的应该就是rCharts包 ...