题意:给定一个串集合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. Hibernate的一对一映射

    一.创建Java工程,新建Lib文件夹,加入Hibernate和数据库(如MySql.Oracle.SqlServer等)的Jar包,创建 hibernate.cfg.xml 文件,并配置,配置项如下 ...

  2. springboot中pageHelper插件 list设置不进去 为null

    分页pageHelper中list放不进去值  为null,可能的解决方案如下: 1. 注意代码顺序,PageHelper.startPage(pageNumber,pageSize)要放在查询Lis ...

  3. 关于安装了sqlite对于vs的组件,重启vs后,在外面可以连接sqlite数据库,但是在建立实体模型时没有sqlite数据源的问题

    出自:http://bbs.csdn.net/topics/390917337 兄弟,刚刚在stackoverflow上找到了解决方法了http://stackoverflow.com/questio ...

  4. Mac配置maven环境命令

    1.安装:解压下载好的maven的文件,解压到你想要的文件夹底下. 2.配置 1)打开终端输入命令 vim ~/.bash_profile (编辑环境变量配置文件) 2)按下i,进入编辑模式 3)在环 ...

  5. C++萃取技术的一个简单初探

    首先本文并不是讲解C++萃取技术,关于C++的萃取技术网上有很多文章,推荐http://www.cppblog.com/woaidongmao/archive/2008/11/09/66387.htm ...

  6. 19-10-28-A

    竟然?竟然?竟然? 我已经用了半个键盘的编号了$\text{T_T}$ $\mathbb{AFO}$感稍强 h1是不是有点大? ZJ+TJ: T1 以为是什么数据结垢,但是是个链表. 所以可以使用 v ...

  7. Windbg 问题集锦记录

    问题1: 问: 0  Id: 15f4.e60 Suspend: 1 Teb: 7ffdf000 Unfrozen  # ChildEBP RetAddr  Args to Child         ...

  8. OpenCASCADE圆与平面求交

    OpenCASCADE圆与平面求交 eryar@163.com 在 解析几何求交之圆与二次曲面中分析了OpenCASCADE提供的类IntAna_IntConicQuad可以用来计算圆与二次曲面之间的 ...

  9. PAT甲级——A1089 Insert or Merge

    According to Wikipedia: Insertion sort iterates, consuming one input element each repetition, and gr ...

  10. apache netbeans不再集成tomcat

    老版本 8.2之前的,集成tomcat,安装使用比较简单https://netbeans.org/features/index.html 新版本的阿帕奇netbeans,则不集成tomcat,使用时, ...