zoukankan      html  css  js  c++  java
  • 【BZOJ1717】产奶的模式(后缀数组)

    【BZOJ1717】产奶的模式(后缀数组)

    题面

    权限题
    hihocoder
    洛谷

    题解

    (hihocoder)里面讲的非常好了


    这题要求的就是最长可重叠重复K次子串

    所谓相同的子串
    我们可以理解为如果有两个后缀的前缀相同
    那么就有一个相同的子串

    如果两个后缀的前缀相同
    那么他们在(SA)中的排名是接近的

    再说清楚点
    如果两个后缀的前缀相同
    必然是在后缀排序中一段连续的后缀都拥有这个相同的前缀

    因此,求出(height)数组之后
    考虑如何计算答案:
    直接搞显然搞不出来
    因此二分一下答案

    如何(check)是否存在长度为(mid)(K)重复子串呢?
    既然是一段连续的区间
    因此,就需要检查是否有超过(K)个连续的(height)(>=mid)

    这个很容易证明:
    如果有(l..r)(height)都超过了(mid)
    那么,证明这一段区间中任意两个后缀的
    (LCP)长度都至少为(mid)
    所以,此时这个(mid)一定出现了超过(K)

    所以,大力二分一下即可

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<set>
    #include<map>
    #include<vector>
    #include<queue>
    using namespace std;
    #define MAX 1200000
    inline int read()
    {
    	int x=0,t=1;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=-1,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return x*t;
    }
    int SA[MAX],Rank[MAX],x[MAX],y[MAX],t[MAX];
    int height[MAX],a[MAX];
    int n,K;
    bool cmp(int i,int j,int k){return y[i]==y[j]&&y[i+k]==y[j+k];}
    void GetSA()
    {
    	int m=1000010;
    	for(int i=1;i<=n;++i)t[x[i]=a[i]]++;
    	for(int i=1;i<=m;++i)t[i]+=t[i-1];
    	for(int i=n;i>=1;--i)SA[t[x[i]]--]=i;
    	for(int k=1;k<=n;k<<=1)
    	{
    		int p=0;
    		for(int i=1;i<=n;++i)y[i]=0;
    		for(int i=n-k+1;i<=n;++i)y[++p]=i;
    		for(int i=1;i<=n;++i)if(SA[i]>k)y[++p]=SA[i]-k;
    		for(int i=0;i<=m;++i)t[i]=0;
    		for(int i=1;i<=n;++i)t[x[y[i]]]++;
    		for(int i=1;i<=m;++i)t[i]+=t[i-1];
    		for(int i=n;i>=1;--i)SA[t[x[y[i]]]--]=y[i];
    		swap(x,y);
    		x[SA[1]]=p=1;
    		for(int i=2;i<=n;++i)x[SA[i]]=cmp(SA[i],SA[i-1],k)?p:++p;
    		if(p>=n)break;
    		m=p;
    	}
    	for(int i=1;i<=n;++i)Rank[SA[i]]=i;
    	for(int i=1,j=0;i<=n;++i)
    	{
    		if(j)j--;
    		while(a[i+j]==a[SA[Rank[i]-1]+j])j++;
    		height[Rank[i]]=j;
    	}
    }
    bool check(int h)
    {
    	int cnt=0;
    	for(int i=2;i<=n;++i)
    	{
    		if(height[i]<h)cnt=0;else cnt++;
    		if(cnt==K-1)return true;
    	}
    	return false;
    }
    int main()
    {
    	n=read();K=read();
    	for(int i=1;i<=n;++i)a[i]=read();
    	GetSA();
    	int l=1,r=n,ans=0;
    	while(l<=r)
    	{
    		int mid=(l+r)>>1;
    		if(check(mid))ans=mid,l=mid+1;
    		else r=mid-1;
    	}
    	printf("%d
    ",ans);
    	return 0;
    }
    
    
  • 相关阅读:
    深入理解DOM事件类型系列第四篇——剪贴板事件
    深入理解DOM事件机制系列第四篇——事件模拟
    利用select实现年月日三级联动的日期选择效果
    深入理解表单脚本系列第四篇——选择框脚本
    存储过程返回布尔值以及C#相关处理
    Type 'Insus.NET.PictureObject' in Assembly 'App_Code, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' is not marked as serializable.
    打开Windows10网络发现或是文件打印共享
    反射(Reflection)的SetValue遇上DBNULL转换为string
    MS SQL中使用UPDATE ... INNER JOIN ...
    Visual Studio 2015正式企业(Enterprise)版
  • 原文地址:https://www.cnblogs.com/cjyyb/p/8336811.html
Copyright © 2011-2022 走看看