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次的模式的长度
Solution
二分+SA/hash
我写的是二分+hash
一个比较明显的性质
对于一个长度为n的串s,s加上某个字符组成一个长度为n+1的串t
t在原串中的出现次数<=s在原串中的出现次数
即关于长度有单调性 可以二分答案长度
然后check一下 把所有长度为mid的串统计个数 看看有没有那种串出现>=k次即可
hash的部分用前缀和做
Code
#include<bits/stdc++.h>
using namespace std;
const int p=69111;
typedef unsigned long long ull;
int a[100010],n,k,ans;
ull fac[100010];
map<ull,int>mp;
ull h[100010];
ull work(int l,int r){
ull s=h[r]-h[l-1]*fac[r-l+1];
return s;
}
bool check(int mid){
int ans=0;
for(int r=mid;r<=n;r++){
int l=r-mid+1;
int s=work(l,r);
mp[s]++;
ans=max(ans,mp[s]);
}
return ans>=k;
}
int rd(){
register int x=0,y=1;
register char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') y=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}
return x*y;
}
int main(){
fac[0]=1;
n=rd(),k=rd();
for(int i=1;i<=n;i++) a[i]=rd();
for(int i=1;i<=n;i++){
fac[i]=fac[i-1]*p;
h[i]=h[i-1]*p+a[i];
}
int l=0,r=n+1;
while(l<r-1){
int mid=(l+r)>>1;
if(check(mid)) l=mid;
else r=mid;
}
printf("%d",l);
}