http://poj.org/problem?id=3261
Milk Patterns
Time Limit: 5000MS Memory Limit: 65536K
Case Time Limit: 2000MS
题目大意:
给定一个数串 ,求至少出现k次的最长重复子串,这k个子串可以重叠。
Input
Line 1: Two space-separated integers:
N and
K
Lines 2.. N+1: N integers, one per line, the quality of the milk on day i appears on the ith line. Output
Line 1: One integer, the length of the longest pattern which occurs at least
K times
Sample Input 8 2 1 2 3 2 3 2 3 1 Sample Output 4 Source |
解法:
网上貌似都是用后缀数组,表示太弱了不会打……
数据比较弱,单Hash水过。
显然,一个数串越长,它可能重复的次数就越少。先二分长度,再用哈希判断同样的数串出现的次数即可。
算次数用map存会TLE,还是老老实实用sort好了。
500K,719MS
//数据较水,单哈希AC
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int inf=20010,p1=139,q1=131,p2=1234567891,q2=1e9+9;
ll hash1[inf],hash2[inf];
int n,k;
int st[inf],top=0;
ll Pow(ll di,ll zh){
ll r=1;
for (;zh;zh>>=1){
if (zh&1) r=r*di%p2;
di=di*di%p2;
}
return r;
}
int gethash1(int i,int j){
return (hash1[j]-(hash1[i-1]*Pow(p1,j-i+1))%p2+p2)%p2;}
/*int gethash2(int i,int j){
return (hash2[j]-(hash2[i-1]*Pow(q1,j-i+1))%q2+q2)%q2;}*/
bool ok(int len){
memset(st,0,sizeof(st)),top=0;
for (int i=1;i+len-1<=n;i++){
st[++top]=gethash1(i,i+len-1);
}
sort(st+1,st+1+top);
for (int i=2,former=st[1],tot=1;i<=top;i++){
if (st[i]==former) tot++;
else former=st[i],tot=1;
if (tot==k) return true;
}
return false;
}
int main(){
cin>>n>>k;
for (int i=1,x;i<=n;i++){
scanf("%d",&x);
hash1[i]=(hash1[i-1]*p1+x)%p2;
// hash2[i]=(hash2[i-1]*q1+x)%q2;
}
int l=1,r=n,ans;
while(l<=r){
int mid=(l+r)>>1;
if (ok(mid)) l=mid+1,ans=mid;
else r=mid-1;
}
cout<<ans;
return 0;
}