[USACO Dec06]产奶的模式
★★ 输入文件:patterns.in
输出文件:
patterns.out
简单对比
时间限制:1 s 内存限制:256 MB
【题目描述】
农夫约翰发现他的奶牛产奶的质量一直在变动。经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠。我们称之为一个“模式”。
约翰的牛奶按质量可以被赋予一个0到1000000之间的数。并且约翰记录了N(1<=N<=20000)天的牛奶质量值。他想知道最长的出现了至少K(2<=K<=N)次的模板的长度。比如1,2,3,2,3,2,3,1中2,3,2,3出现了两次。当K=2时,这个长度为4.
【输入格式】
第1行输入两个整数N和K。接下来N行每行一个整数表示当天的产奶质量。
【输出格式】
一个整数:N天中最长的出现了至少K次的模式的长度。
【样例输入】
8 2 1 2 3 2 3 2 3 1
【样例输出】
4
【来源】
USACO Dec06 Gold Milk Patterns
Coaches,2004
Translate by:庄乐
我们一直熟悉的二分判断可行性,好写,简单。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 20010
using namespace std;
int n,k,m;
int s[maxn],sa[maxn],t1[maxn],t2[maxn],cnt[1000010];
int h[maxn],r[maxn];
void Suffix_Sort(){
int *x=t1,*y=t2,i;
for(i=0;i<m;i++)cnt[i]=0;
for(i=0;i<n;i++)cnt[x[i]=s[i]]++;
for(i=0;i<m;i++)cnt[i]+=cnt[i-1];
for(i=0;i<n;i++)sa[--cnt[s[i]]]=i;
for(int k=1;k<=n;k<<=1){
int p=0;
for(i=n-k;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)
if(sa[i]>=k)y[p++]=sa[i]-k;
for(i=0;i<m;i++)cnt[i]=0;
for(i=0;i<n;i++)cnt[x[y[i]]]++;
for(i=0;i<m;i++)cnt[i]+=cnt[i-1];
for(i=n-1;i>=0;i--)sa[--cnt[x[y[i]]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++)x[sa[i]]=
y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?
p-1:p++;
if(p>=n)break;m=p;
}
}
void Query_Height(){
for(int i=0;i<n;i++)r[sa[i]]=i;
int k=0,j;
for(int i=0;i<n;i++){
if(!r[i])continue;
if(k)k--;j=sa[r[i]-1];
while(s[i+k]==s[j+k])k++;
h[r[i]]=k;
}//h[0]=0;
}
bool Judge(int len){
int c=0;
for(int i=1;i<n;i++){
c= h[i]>=len?c+1:0;
if(c>=k-1)return true;
}return false;
}
int main(){
freopen("patterns.in","r",stdin);
freopen("patterns.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++){
scanf("%d",&s[i]);
m=max(m,s[i]);
}m++;s[n]=-1;
Suffix_Sort();
Query_Height();
int l=0,r=n,mid;
while(l<=r){
mid=(l+r)>>1;
Judge(mid)?l=mid+1:r=mid-1;
}
printf("%d",l-1);
return 0;
}
自然还是有别的法子的。单调队列优化!
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 20010
using namespace std;
int n,k,m;
int s[maxn],sa[maxn],t1[maxn],t2[maxn],cnt[1000010];
int h[maxn],r[maxn];
void Suffix_Sort(){
int *x=t1,*y=t2,i;
for(i=0;i<m;i++)cnt[i]=0;
for(i=0;i<n;i++)cnt[x[i]=s[i]]++;
for(i=0;i<m;i++)cnt[i]+=cnt[i-1];
for(i=0;i<n;i++)sa[--cnt[s[i]]]=i;
for(int k=1;k<=n;k<<=1){
int p=0;
for(i=n-k;i<n;i++)y[p++]=i;
for(i=0;i<n;i++)
if(sa[i]>=k)y[p++]=sa[i]-k;
for(i=0;i<m;i++)cnt[i]=0;
for(i=0;i<n;i++)cnt[x[y[i]]]++;
for(i=0;i<m;i++)cnt[i]+=cnt[i-1];
for(i=n-1;i>=0;i--)sa[--cnt[x[y[i]]]]=y[i];
p=1;swap(x,y);x[sa[0]]=0;
for(i=1;i<n;i++)x[sa[i]]=
y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?
p-1:p++;
if(p>=n)break;m=p;
}
}
void Query_Height(){
for(int i=0;i<n;i++)r[sa[i]]=i;
int k=0,j;
for(int i=0;i<n;i++){
if(!r[i])continue;
if(k)k--;j=sa[r[i]-1];
while(s[i+k]==s[j+k])k++;
h[r[i]]=k;
}//h[0]=0;
}
int head,tail;
int que[maxn],pos[maxn];
void push(int p,int x){
while(head<=tail&&que[tail]>=x)tail--;
pos[++tail]=p,que[tail]=x;
}
int main(){
freopen("patterns.in","r",stdin);
freopen("patterns.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++){
scanf("%d",&s[i]);
m=max(m,s[i]);
}m++;s[n]=-1;
Suffix_Sort();
Query_Height();
int ans=0;
k--;
//for(int i=0;i<n;i++)cout<<h[i]<<' ';
for(int i=0;i<k;i++)push(i,h[i]);
ans=que[head];
for(int i=k;i<=n-k;i++){
while(head<=tail&&pos[head]<=i-k)head++;
push(i,h[i]);
ans=max(ans,que[head]);
//cout<<que[head]<<' ';
}
printf("%d",ans);
return 0;
}