题意:给定一个串集合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. 服务器访问数据库表mysql

    服务器的MySQL配置就不说了,直接说一些用到的基础命令 登陆 show databases; use 数据库: show tables; 执行sql即可: 一定要有分号 select * from ...

  2. open 和 release

    我们开始在真实的 scull 函数中使用它们. open 方法   open 方法提供给驱动来做任何的初始化来准备后续的操作. 在大部分驱动中, open 应当 进行下面的工作: 检查设备特定的错误( ...

  3. 74CMS漏洞打包(从老博客转)

    引子 这套CMS是上个月中做的审计,总共找到几个后台漏洞,可后台getshell,一个逻辑漏洞可任意发短信,还有一个前台注入漏洞.不过发到了某平台上之后,审核又要求我提交利用的poc,所以懒得发去了, ...

  4. Widget Factory

    Widget Factory 有N种零件,生产所需天数都为3~9天,有M条记录,记录开工星期几,和停工星期几,并告诉你这条记录所加工的零件,求每种零件的生产时间,\(1≤N,M≤300\). 解 显然 ...

  5. Linux下常用操作

    ************************ 镜像操作 ************************************* screen -s name 新建 screen -r name ...

  6. 17多校6 HDU - 6102

    题意:给一个排列p,m次查询l,r,\(\sum_{i=l}^r\sum_{j=i+1}^r\sum_{k=j+1}^r[gcd(p_i,p_j)==p_k]p_k\) 题解:离线,枚举右端点,对于每 ...

  7. Django之深入了解路由层

    目录 ORM表关系建立 一对一 一对多 多对多 Django 请求生命周期 url 路由层 路由匹配 无名分组 有名分组 反向解析 路由匹配条件无分组的情况的反向解析 无名分组情况的反向解析 有名分组 ...

  8. 容斥原理——hdu2841

    记得要开ll /* 莫比乌斯反演模板题,也可以直接算phi来做 容斥的解法 求x[1..m],在[1,n]中和其互质的数的个数即可 那么就是n-和x不互质的数个数即可 */ #include<b ...

  9. opencv3 使用glob遍历并修改文件名

    1.函数说明 string::find()函数:是一个字符或字符串查找函数,该函数有唯一的返回类型,即string::size_type,即一个无符号整形类型,可能是整数也可能是长整数.如果查找成功, ...

  10. 自己编写jquery插件

    http://blog.csdn.net/chenxi1025/article/details/52222327 https://www.cnblogs.com/ajianbeyourself/p/5 ...