zoukankan      html  css  js  c++  java
  • bzoj1717 [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
     
    也是SA
    height[i]表示字典序排第i的串和字典序排i-1的串的最长公共前缀
    然后有一个结论是height[i]>=height[i-1]-1
    而且按照后缀的下标排序的话可以让复杂度降到O(n)
    具体见2009罗穗骞论文《后缀数组——处理字符串的有力工具》
    这题求最长可重复前缀,注意到一旦height[i]<k,那么不可能有一个满足条件的子串同时包含i和i-1
    二分答案x,然后统计height[i]>=x的最长连续的一段,如果超过m就可行
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define N 40010
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int srt[N],a[N],hash[N],h[N],ht[N];
    int sa[2][N],rnk[2][N],v[N];
    int n,m,k,tt,p,q,ans;
    inline void calc_sa(int sa[N],int rnk[N],int SA[N],int RNK[N])
    {
    	for (int i=1;i<=n;i++)v[rnk[sa[i]]]=i;
    	for (int i=n;i>=1;i--)if (sa[i]>k)SA[v[rnk[sa[i]-k]]--]=sa[i]-k;
    	for (int i=n-k+1;i<=n;i++)SA[v[rnk[i]]]=i;
    	for (int i=1;i<=n;i++)
    	RNK[SA[i]]=RNK[SA[i-1]]+(rnk[SA[i]]!=rnk[SA[i-1]]||rnk[SA[i]+k]!=rnk[SA[i-1]+k]);
    }
    inline void get_sa()
    {
    	p=0;q=1;a[0]=-1;
    	memset(v,0,sizeof(v));
    	for (int i=1;i<=n;i++)v[a[i]]++;
    	for (int i=1;i<=n;i++)v[i]+=v[i-1];
    	for (int i=1;i<=n;i++)sa[p][v[a[i]]--]=i;
    	for (int i=1;i<=n;i++)
    		rnk[p][sa[p][i]]=rnk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
    	for (k=1;k<n;k<<=1,swap(p,q))
    		calc_sa(sa[p],rnk[p],sa[q],rnk[q]);
    }
    inline void get_h()
    {
    	k=0;
    	for(int i=1;i<=n;i++)
    	{
    		if (rnk[p][i]==1)h[i]=0;
    		else
    		{
    			int j=sa[p][rnk[p][i]-1];
    			while (a[i+k]==a[j+k])k++;
    			h[i]=k;if (k)k--;
    		}
    	}
    	for (int i=1;i<=n;i++)
    		ht[rnk[p][i]]=h[i];
    }
    inline bool jud(int x)
    {
    	int temp=0;
    	for (int i=1;i<=n;i++)
    	{
    		if (ht[i]>=x){temp++;if (temp==m-1)return 1;}
    		else temp=0;
    	}
    	return 0;
    }
    int main()
    {
    	n=read();m=read();
    	for (int i=1;i<=n;i++)srt[i]=a[i]=read();
    	sort(srt+1,srt+n+1);srt[0]=-1;
    	hash[++tt]=srt[1];
    	for (int i=2;i<=n;i++)if (srt[i]!=srt[i-1])hash[++tt]=srt[i];
    	for (int i=1;i<=n;i++)a[i]=lower_bound(hash+1,hash+tt+1,a[i])-hash;
    	get_sa();
    	get_h();
    	int l=1,r=n;
    	while (l<=r)
    	{
    		int mid=(l+r)>>1;
    		if (jud(mid)){ans=mid;l=mid+1;}
    		else r=mid-1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    

      

    ——by zhber,转载请注明来源
  • 相关阅读:
    JavaScript中的闭包
    正则表达式(括号)、[中括号]、{大括号}的区别
    写出将字符串中的数字转换为整型的方法,如:“as31d2v”->312,并写出相应的单元测试,正则去掉非数值、小数点及正负号外的字符串
    正则替换实现字符串链接每4位用“-”连接成新的字符串
    memcache搭建
    MySQL优化
    网络优化
    JDK配置及tomcat部署
    oracle中增加pga和sga
    sudo用法
  • 原文地址:https://www.cnblogs.com/zhber/p/4223113.html
Copyright © 2011-2022 走看看