zoukankan      html  css  js  c++  java
  • [BZOJ 1717] [USACO06DEC]Milk Patterns产奶模式(后缀数组+单调队列)

    [BZOJ 1717] [USACO06DEC]Milk Patterns产奶模式(后缀数组+单调队列)

    题面

    农夫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。

    分析

    模式串肯定是某两个后缀的LCP,那么显然选rank相邻的两个后缀,重复的部分尽量多,这样会更优。因此,出现了K次的模式串就对应了height数组上长度为K-1的一段连续区间(由于height是相邻两个后缀的LCP,一共K个后缀,有K-1个“间隙).长度就是区间中的最小值。

    那么问题就变成求height数组上找一个长度为K-1的区间,使得区间内的最小值最大。可以用单调队列解决。

    代码

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #define maxn 1000000 
    using namespace std;
    int n,k,dn;
    int s[maxn+5];
    void rsort(int *ans,int *fi,int *se,int sz,int maxv){
    	static int buck[maxn+5];
    	for(int i=0;i<=maxv;i++) buck[i]=0;
    	for(int i=1;i<=n;i++) buck[fi[i]]++;
    	for(int i=1;i<=maxv;i++) buck[i]+=buck[i-1];
    	for(int i=n;i>=1;i--) ans[buck[fi[se[i]]]--]=se[i];
    }
    int sa[maxn+5],rk[maxn+5],height[maxn+5];
    void suffix_sort(int *str,int n,int m){
    	static int se[maxn+5];
    	for(int i=1;i<=n;i++){
    		rk[i]=str[i];
    		se[i]=i;
    	}
    	rsort(sa,rk,se,n,dn);
    	for(int k=1;k<=n;k*=2){
    		int p=0;
    		for(int i=n-k+1;i<=n;i++) se[++p]=i;
    		for(int i=1;i<=n;i++) if(sa[i]>k) se[++p]=sa[i]-k;
    		rsort(sa,rk,se,n,m);
    		swap(rk,se);
    		p=rk[sa[1]]=1;
    		for(int i=2;i<=n;i++){
    			if(se[sa[i-1]]==se[sa[i]]&&se[sa[i-1]+k]==se[sa[i]+k]) rk[sa[i]]=p;
    			else rk[sa[i]]=++p; 
    		} 
    		if(p==n) break;
    		m=p;
    	}
    }
    void get_height(int *str,int n){
    	suffix_sort(str,n,dn);
    	for(int i=1;i<=n;i++) rk[sa[i]]=i;
    	int k=0;
    	for(int i=1;i<=n;i++){
    		if(k) k--;
    		int j=sa[rk[i]-1];
    		while(str[i+k]==str[j+k]) k++;
    		height[rk[i]]=k;
    	}
    }
    
    int discrete(int* a,int n){
    	static int tmp[maxn+5];
    	int sz;
    	for(int i=1;i<=n;i++) tmp[i]=a[i];
    	sort(tmp+1,tmp+1+n);
    	sz=unique(tmp+1,tmp+1+n)-tmp-1;
    	for(int i=1;i<=n;i++) a[i]=lower_bound(tmp+1,tmp+1+sz,a[i])-tmp;
    	return sz;
    }
    
    int slide_window(int *a,int n,int k){
    	static int q[maxn+5];
    	int head=1,tail=0;
    	int ans=0;
    	for(int i=1;i<=k;i++){
    		while(head<=tail&&a[i]<a[q[tail]]) tail--;
    		q[++tail]=i;
    	}
    	for(int i=k+1;i<=n;i++){
    		while(head<=tail&&q[head]<=i-k) head++;
    		while(head<=tail&&a[i]<a[q[tail]]) tail--;
    		q[++tail]=i; 
    		ans=max(ans,a[q[head]]);
    	}
    	return ans;
    } 
    int main(){
    	scanf("%d %d",&n,&k);
    	for(int i=1;i<=n;i++) scanf("%d",&s[i]);
    	dn=discrete(s,n);
    	get_height(s,n);
    	printf("%d
    ",slide_window(height,n,k-1));
    } 
    
  • 相关阅读:
    第三章读书笔记
    第二章读书笔记
    第一章读书笔记
    第四章读书笔记
    《android深入探索》第一章心得
    C语言I博客作业04
    C语言I博客作业03
    C语言I博客作业02
    C语言I博客作业4
    C语言博客作业3
  • 原文地址:https://www.cnblogs.com/birchtree/p/12221161.html
Copyright © 2011-2022 走看看