题意:给定一个串集合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. selenium基础(下拉菜单操作)

    selenium基础(下拉菜单操作) 非select/option元素: 1.触发下拉列表出现 2.等待下拉列表中的元素出现,然后进行选择元素即可. select/option元素: 下拉框操作-Se ...

  2. springcloud ribbon Finchley 版本,自定义算法

    引用上一个项目,在原有的基础上进行更改,添加springcloud的内荣. eureka-server 和上一个springcloud eureka的一样,没有改动. 添加cloud-api pack ...

  3. COGITATE | 分析当前热门软件的创新

    热门软件分析实例一——Github [简介] gitHub是一个面向开源及私有软件项目的托管平台,因为只支持git 作为唯一的版本库格式进行托管,故名gitHub.作为一个分布式的版本控制系统,在Gi ...

  4. SQL中的左连接与右连接,内连接有什么不同

    SQL中的左连接与右连接,内连接有什么不同 我们来举个例子.天庭上面有一个管理系统:管理系统有个主表:主表记录着各个神仙的基本信息(我们把它当成表A).还有个表记录着他们这个神仙的详细信息(我们把它当 ...

  5. h5 上下左右前后居中

    .outer { width: 200px; height: 200px; background: red; position: relative; } .inner { position: abso ...

  6. Struts2基本总结

    现在Struts2慢慢退出舞台了,但是很多项目还需要用Struts2进行开发和维护,这里就简单的重新快速的掌握这门技术 Struts2的相关配置文件 * default.properties     ...

  7. IDA*算法——骑士精神

    例题 骑士精神 Description 在一个5×5的棋盘上有12个白色的骑士和12个黑色的骑士, 且有一个空位.在任何时候一个骑士都能按照骑士的走法(它可以走到和它横坐标相差为1,纵坐标相差为2或者 ...

  8. 移动端,fixed bottom问题

    //不显示 .bar { position:fixed; bottom:0; z-index:99; } //显示 .bar{ position:fixed; bottom:calc(90vh); / ...

  9. Go基础之函数递归实现汉诺塔

    Go递归实现汉诺塔 package main import "fmt" // a 是源,b 借助, c 目的长度 func tower(a, b, c string, layer ...

  10. mysql插入数据显示:Incorrect datetime value: '0000-00-00 00:00:00'

    1. 在进行mysql数据插入的时候,由于mysql的版本为5.7.1,部分功能已经升级,导致在datetime数据类型的影响下出现错误:   数据插入: mysql>insert into j ...