bzoj 1717 [Usaco2006 Dec]Milk Patterns 产奶的模式

1717: [Usaco2006 Dec]Milk Patterns 产奶的模式

Time Limit: 5 Sec   Memory Limit: 64 MB
Submit: 1222   Solved: 660
[ Submit][ Status][ Discuss]

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

HINT

Source

Gold



【分析】

后缀数组+二分答案

观察到如果i为可行长度,那么1~i一定都是可行长度(废话),所以我们可以二分最长长度,每次扫一遍height数组,如果满足连续K-1个height>=mid(二分的长度),那么mid就是一个可行解~



【代码】

//bzoj 1717 [Usaco2006 Dec]Milk Patterns 产奶的模式
#include
#include
#include
#include
#define ll long long
#define M(a) memset(a,0,sizeof a)
#define fo(i,j,k) for(i=j;i<=k;i++)
using namespace std;
const int mxn=20005;
int n,m,K,len;
char s[mxn];
int a[mxn],b[1000005],x[mxn],y[mxn],sa[mxn],rank[mxn],height[mxn];
inline bool comp(int i,int j,int l)
{
    return y[i]==y[j]&&(i+l>len?-1:y[i+l])==(j+l>len?-1:y[j+l]);
}
inline void work()
{
    int i,j,k,p;m=1000000;
    fo(i,0,m) b[i]=0;
    fo(i,1,len) b[x[i]=a[i]]++;
    fo(i,1,m) b[i]+=b[i-1];
    for(i=len;i>=1;i--) sa[b[x[i]]--]=i;
    for(k=1;k<=len;k<<=1)
    {
        p=0;
        fo(i,len-k+1,len) y[++p]=i;
        fo(i,1,len) if(sa[i]>k) y[++p]=sa[i]-k;
        fo(i,0,m) b[i]=0;
        fo(i,1,len) b[x[y[i]]]++;
        fo(i,1,m) b[i]+=b[i-1];
        for(i=len;i>=1;i--) sa[b[x[y[i]]]--]=y[i];
        swap(x,y),p=2,x[sa[1]]=1;
        fo(i,2,len)
          x[sa[i]]=comp(sa[i-1],sa[i],k)?p-1:p++;
        if(p>len) break;
        m=p;
    }
    p=k=0;
    fo(i,1,len) rank[sa[i]]=i;
    for(i=1;i<=len;height[rank[i++]]=k)
      for(k?k--:0,j=sa[rank[i]-1];a[i+k]==a[j+k];k++);
}
inline bool ok(int mid)
{
	int cnt=1,i,j;
	fo(i,2,len)
	{
		if(height[i]=K) return 1;
	}
	return 0;
}
int main()
{
	int i,j;
	scanf("%d%d",&len,&K);
	fo(i,1,len) scanf("%d",&a[i]);
	work();
	int l=1,r=len;
	while(l>1;
		if(ok(mid)) l=mid;
		else r=mid-1;
	}
	printf("%d\n",l);
	return 0;
}
//Have I found you? Flightless bird,jealous weeping.
//or lost you? American mouth.Big pill,looming.

你可能感兴趣的:(后缀数组,二分)