[Usaco2006 Dec]Milk Patterns

Description

农夫John发现他的奶牛产奶的质量一直在变动。经过细致的调查,他发现:虽然他不能预见明天 
产奶的质量,但连续的若干天的质量有很多重叠。我们称之为一个“模式”。 
John的牛奶按质量可以被赋予一个0到1000000之间的数。并且John记录了N(1<=N<=20000)天的 
牛奶质量值。他想知道最长的出现了至少K(2<=K<=N)次的模式的长度。 
比如1 2 3 2 3 2 3 1 中 2 3 2 3出现了两次。当K=2时,这个长度为4。

Input

* Line 1: 两个整数 N,K。 
* Lines 2..N+1: 每行一个整数表示当天的质量值。

Output

* Line 1: 一个整数:N天中最长的出现了至少K次的模式的长度

Sample Input

8 2
1
2
3
2
3
2
3
1

Sample Output

4

Source

后缀数组

答案应该是height数组中连续K-1个值的最小值的最大值。

这题还是要先离散化一下,不然可能会MLE

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 30010
using namespace std;
char ch;
int n,k,max_val,tot,head,tail,s[maxn],num[maxn],SA[maxn],rank[maxn],tmp[maxn],sum[maxn],height[maxn];
struct DATA{
	int val,tim;
}list[maxn];
inline bool isdigit(char ch){return ‘0‘<=ch&&ch<=‘9‘;}
inline void read(int &x){
	for (ch=getchar();!isdigit(ch);ch=getchar());
	for (x=0;isdigit(ch);x=x*10+ch-‘0‘,ch=getchar());
}
inline bool cmp(int a,int b){return s[a]<s[b];}
void prepare(){
	sort(num+1,num+1+n,cmp);
	for (int i=1,pre=-1;i<=n;i++){
		if (s[num[i]]!=pre) pre=s[num[i]],++max_val;
		s[num[i]]=max_val;
	}
}
void get_SA(){
	for (int i=1;i<=n;i++) sum[tmp[i]=s[i]]++;
	for (int i=1;i<=max_val;i++) sum[i]+=sum[i-1];
	for (int i=n;i>=1;i--) SA[sum[tmp[i]]--]=i;
	rank[SA[1]]=tot=1;
	for (int i=2;i<=n;i++){
		if (tmp[SA[i]]!=tmp[SA[i-1]]) tot++;
		rank[SA[i]]=tot;
	}
	for (int len=1;len<=n;len<<=1){
		memset(sum,0,sizeof(sum));
		for (int i=1;i<=n;i++) sum[rank[i+len]]++;
		for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
		for (int i=n;i>=1;i--) tmp[sum[rank[i+len]]--]=i;
		memset(sum,0,sizeof(sum));
		for (int i=1;i<=n;i++) sum[rank[tmp[i]]]++;
		for (int i=1;i<=n;i++) sum[i]+=sum[i-1];
		for (int i=n;i>=1;i--) SA[sum[rank[tmp[i]]]--]=tmp[i];
		tmp[SA[1]]=tot=1;
		for (int i=2;i<=n;i++){
			if (rank[SA[i]]!=rank[SA[i-1]]||rank[SA[i]+len]!=rank[SA[i-1]+len]) tot++;
			tmp[SA[i]]=tot;
		}
		for (int i=1;i<=n;i++) rank[i]=tmp[i];
	}
}
void get_height(){
	for (int i=1,j=0;i<=n;i++){
		if (rank[i]==1) continue;
		while (s[i+j]==s[SA[rank[i]-1]+j]) j++;
		height[rank[i]]=j;
		if (j>0) j--;
	}
}
int main(){
	read(n),read(k);
	for (int i=1;i<=n;i++) read(s[i]),num[i]=i;
	prepare(),get_SA(),get_height();
	k--,head=1,tail=0,max_val=0;
	for (int i=2;i<=n;i++){
		while (head<=tail&&i-list[head].tim>=k) head++;
		while (head<=tail&&height[i]<list[tail].val) tail--;
		list[++tail]=(DATA){height[i],i};
		if (i>k&&max_val<list[head].val) max_val=list[head].val;
	}
	printf("%d\n",max_val);
	return 0;
}
时间: 2024-08-11 20:32:30

[Usaco2006 Dec]Milk Patterns的相关文章

[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

BZOJ 1717: [Usaco2006 Dec]Milk Patterns 产奶的模式 [后缀数组]

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

BZOJ 1717: [Usaco2006 Dec]Milk Patterns 产奶的模式( 二分答案 + 后缀数组 )

二分答案m, 后缀数组求出height数组后分组来判断. ------------------------------------------------------------ #include<bits/stdc++.h> using namespace std; const int maxn = 20009; struct HASH { int id[maxn], N; HASH() { N = 0; } inline void work() { sort(id, id + N); N

[bzoj1717][Usaco2006 Dec]Milk Patterns 产奶的模式_后缀数组_二分答案

Milk Patterns 产奶的模式 bzoj-1717 Usaco-2006 Dec 题目大意:给定一个字符串,求最长的至少出现了$k$次的子串长度. 注释:$1\le n\le 2\cdot 10^4$,$2\le k\le n$. 想法:不难想到二分答案,现在我们考虑如何验证. 这里就是后缀数组的一个妙用了. 我们对原串建立后缀数组,观察$ht$数组. 考虑当前二分出来的$mid$.如果有至少连续$k$的$ht$值都不小于$mid$,那么$k$就是合法的. 故此我们直接扫$ht$数组看看

【BZOJ1717】[Usaco2006 Dec]Milk Patterns 产奶的模式 (二分+SA)

求重复k次的最长重复子串,解法见罗穗骞大神的后缀数组论文 1 const maxn=100419; 2 3 var 4 x,y,rank,sa,h,s,num,c:array[0..maxn] of longint; 5 n,time:longint; 6 7 function max(x,y:longint):longint; begin if x>y then exit(x) else exit(y); end; 8 function min(x,y:longint):longint; be

BZOJ 1717 [Usaco2006 Dec]Milk Patterns 产奶的模式(后缀数组)

[题目链接]http://www.lydsy.com/JudgeOnline/problem.php?id=1717 [题目大意] 求一个最长的串,使得其在母串中出现的次数达到要求 [题解] 二分答案,利用后缀数组求出的height数组进行检验 [代码] #include <cstdio> #include <cstring> using namespace std; const int N=2000010; int n,k,rank[N],sa[N],h[N],tmp[N],cn

bzoj1717: [Usaco2006 Dec]Milk Patterns 产奶的模式(后缀数组+二分)

1 /* 2 求可重叠的至少重复K次的最长字串 3 以1为下标起点,因为a[i]最大到1000000,所以要先离散一下 4 二分长度len 5 然后O(n)检验 6 后看h[i]是否有连续的一段h[i]大于len的,并且h[i]连续的长度大于K则满足 7 */ 8 #include<stdio.h> 9 #include<string.h> 10 #include<algorithm> 11 using namespace std; 12 const int maxn

[bzoj1717][Usaco2006 Dec]Milk Patterns 产奶的模式 (hash构造后缀数组,二分答案)

以后似乎终于不用去学后缀数组的倍增搞法||DC3等blablaSXBK的方法了= = 定义(来自关于后缀数组的那篇国家集训队论文..) 后缀数组:后缀数组SA是一个一维数组,它保存1..n的某个排列SA[1],SA[2],……,SA[n],并且保证Suffix(SA[i])<Suffix(SA[i+1]),1≤i<n. 也就是将S的n个后缀从小到大进行排序之后把排好序的后缀的开头位置顺次放入SA中. height数组:定义height[i]=suffix(sa[i-1])和suffix(sa[

【SuffixArray】bzoj1717 [Usaco2006 Dec] Milk Patterns 产奶的模式

传送门:BZOJ1717 解题思路 先把正解说一说:单调队列或者二分 然后么..为什么我写的这么长?! 是罗穗骞的论文题嘛--就当给后缀数组练手吧 可重叠k次重复字串 YM代码 #include <bits/stdc++.h> using namespace std; #define rep(i, a, b) for(int i = (a); i <= (b); i++) #define red(i, a, b) for(int i = (a); i >= (b); i--) #d