Luogu2852 [USACO06DEC]牛奶模式

题目蓝链

Description

给定一个字符串,你需要找到一个最长在这个串中至少出现了\(k\)次的子串

Solution

我们首先对这个串进行后缀排序,那么对于排序后的任意一个区间\([l, r]\),那么原串中一定有\(r - l + 1\)个长度为\(MIN_{i \in (l, r]} \{height_i\}\)的相同字串

于是我们就直接把\(height\)数列扫一边,同时维护一个单调队列,来维护任意相邻的\(k - 1\)个\(height\)的最小值,答案便是这些最小值中的最大值

Code

#include <bits/stdc++.h>

using namespace std;

#define fst first
#define snd second
#define mp make_pair
#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef pair<int, int> pii;

template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }

inline int read() {
    int sum = 0, fg = 1; char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
    for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
    return fg * sum;
}

const int maxn = 2e4 + 10;
const int maxm = 1e6 + 10;

int n, m, k;
int S[maxn], sa[maxn], buc[maxm], rk[maxn], tmp[maxn], height[maxn];

inline void Radix_sort() {
    for (int i = 1; i <= m; i++) buc[i] = 0;
    for (int i = 1; i <= n; i++) ++buc[rk[i]];
    for (int i = 1; i <= m; i++) buc[i] += buc[i - 1];
    for (int i = n; i >= 1; i--) sa[buc[rk[tmp[i]]]--] = tmp[i];
}

inline void get_sa() {
    for (int i = 1; i <= n; i++) rk[i] = S[i] + 1, tmp[i] = i;
    m = 1e6 + 1, Radix_sort();
    for (int k = 1; k <= n; k <<= 1) {
        int p = 0;
        for (int i = n - k + 1; i <= n; i++) tmp[++p] = i;
        for (int i = 1; i <= n; i++) if (sa[i] > k) tmp[++p] = sa[i] - k;
        Radix_sort(), swap(rk, tmp);
        rk[sa[1]] = 1, m = 1;
        for (int i = 2; i <= n; i++)
            rk[sa[i]] = (tmp[sa[i]] == tmp[sa[i - 1]] && tmp[sa[i] + k] == tmp[sa[i - 1] + k]) ? m : ++m;
        if (m >= n) break;
    }
}

inline void get_height() {
    for (int i = 1, k = 0; i <= n; i++) {
        if (k) --k;
        int j = sa[rk[i] - 1];
        while (S[i + k] == S[j + k]) ++k;
        height[rk[i]] = k;
    }
}

int main() {
#ifdef xunzhen
    freopen("milk.in", "r", stdin);
    freopen("milk.out", "w", stdout);
#endif

    n = read(), k = read();
    for (int i = 1; i <= n; i++) S[i] = read();
    get_sa(), get_height();

    deque<int> q;
    int ans = 0;
    for (int i = 2; i <= n; i++) {
        while (!q.empty() && height[q.back()] > height[i]) q.pop_back();
        q.push_back(i);
        while (!q.empty() && q.front() <= i - k + 1) q.pop_front();
        chkmax(ans, height[q.front()]);
    }
    cout << ans << endl;

    return 0;
}

原文地址:https://www.cnblogs.com/xunzhen/p/10614197.html

时间: 2024-11-10 16:11:33

Luogu2852 [USACO06DEC]牛奶模式的相关文章

[Luogu2852][USACO06DEC]牛奶模式Milk Patterns

Luogu 一句话题意 给出一个串,求至少出现了\(K\)次的子串的最长长度. sol 对这个串求后缀数组. 二分最长长度. 如果有\(K\)个不同后缀他们两两的\(lcp\)都\(>=mid\) 那么他们在\(SA\)中一定排在连续的一段区间,且两两之间的\(Height[i]>=mid\) 所以判断\(Height\)数组中是否存在长度大于等于\(K-1\)且数值全部大于等于\(mid\)的连续段. code #include<cstdio> #include<algor

洛谷P2852 [USACO06DEC]牛奶模式Milk Patterns

题目描述 Farmer John has noticed that the quality of milk given by his cows varies from day to day. On further investigation, he discovered that although he can't predict the quality of milk from one day to the next, there are some regular patterns in th

USACO06DEC 牛奶模式

题意:求最长的可重叠的 K重复子串 的长度 考虑二分长度s,转化为验证性问题. 对SA进行分组.保证组内Height最小为s.这样在组内RMQ就可以任意了,因为RMQ一定是大于S的. 只要组内元素个数大于等于K就是可行解. 1 #include <bits/stdc++.h> 2 using namespace std; 3 4 struct SA{ 5 int str[1000005]; 6 int x[1000005],y[1000005],u[1000005],v[1000005],r[

题解-牛奶模式

(〇)题目描述 题目传送门 简单讲解一下题意: 给出一个字符串,求最长至少出现了 \(k\) 的子串(可重叠). (一)解题思路 这题需要我们在一个模式串中找相同的子串,很容易就能想到后缀数组. 那么,如何找至少重复出现 \(k\) 次的子串呢? 考虑二分子串的长度,看看答案是否具有单调性. 如果长度为 \(len\) 的子串出现了 \(k\) 次,那么一定有长度小于 \(len\) 的子串出现了 \(k\) 次(这些子串可以是长度为 \(len\) 的子串的子串) 这样题目就变成了判定性问题,

2019年7月博客汇总下

[ZJOI2007]捉迷藏 这是我最近写过最长的代码QAQ 码力太弱了QAQ 动态点分治模板题. 我们可以用三种堆来维护答案,这些堆要求支持删除非顶元素,以及查询次小值.我们把两个STL堆封装起来就可以实现. 三种堆: d[x]表示以x为根的点分树中所有黑点到它分治爹的距离 c[x]表示以x为根的所有点分儿子d堆中的最大值 ans表示全局的最大值 我们从c中取出最大值和次大值就可以得到过这个点分根的最长链.我们不断用它来更新答案. 注意d的定义是到分治父亲的父亲的最大值 c数组要加入一个0 Co

后缀数组题目

巨佬博客: https://www.cnblogs.com/zwfymqz/p/8413523.html #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+10; int n,M,sa[N],rk[N],tp[N],sum[N],hight[N]; char s[N]; void Qsort() { for(int i=0;i<=M;i++) sum[i]=0; for(i

[BZOJ1717][Usaco2006 Dec]Milk Patterns 产奶的模式

1717: [Usaco2006 Dec]Milk Patterns 产奶的模式 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1297  Solved: 705 [Submit][Status][Discuss] Description 农夫John发现他的奶牛产奶的质量一直在变动.经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠.我们称之为一个"模式". John的牛奶按质量可以被赋予一个0到100

《JavaScript设计模式与开发实践》读书笔记之模板方法模式

1. 模板方法模式 1.1 面向对象方式实现模板方法模式 以泡茶和泡咖啡为例,可以整理为下面四步 把水煮沸 用沸水冲泡饮料 把饮料倒进杯子 加调料 首先创建一个抽象父类来表示泡一杯饮料 var Beverage=function(){}; Beverage.prototype.boilWater=function(){ console.log('把水煮沸'); }; Beverage.prototype.brew=function(){};//空方法,由子类重写 Beverage.prototy

设计模式5 行为模式

行为模式,目录: 模式方法模式 命令模式 策略模式观察者模式 模板方法模式:冲咖啡,冲茶水 [email protected]:~$ cat main.cpp  #include <iostream> using namespace std; //抽象的制作饮料方法 class MakeDrink { public: //1 把水煮开 void boil() { cout << "把水煮开" << endl; } //2 冲某物 virtual vo