您的位置:首页 > 其它

UVALive4513 Stammering Aliens(哈希法,后缀数组)

2015-12-10 17:36 525 查看
题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=12580

【思路】

求出现次数不小于k次的最长可重叠子串和最后的出现位置。

法一:

后缀数组,二分长度,划分height。时间复杂度为O(nlogn)

法二:

Hash法。构造字符串的hash函数,二分长度,求出hash(i,L)后排序,判断是否存在超过k个相同hash 值得块即可。时间为O(nlog2n).

   法三:(UPD.16/4/6)

     SAM。求|right|。

注意划分height一定要精确且如果m=1需要特判

【代码1】

//1628ms
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;

typedef unsigned long long ULL;
const int maxn = 80000+10;
const int x = 233;

ULL hash[maxn],xp[maxn],H[maxn];
int m,n;
char s[maxn];

int cmp(const int& a,const int& b) {
return hash[a]<hash[b] || (hash[a]==hash[b] && a<b);
}
int pos,rank[maxn];
bool can(int L) {
pos=-1;
for(int i=0;i<n-L+1;i++) hash[i]=H[i]-H[i+L]*xp[L],rank[i]=i;
sort(rank,rank+n-L+1,cmp);
int cnt=0;
for(int i=0;i<n-L+1;i++) {
if(!i || hash[rank[i]]!=hash[rank[i-1]]) cnt=0;
if(++cnt>=m) pos=max(pos,rank[i]);
}
return pos>=0;
}

int main() {
//freopen("in.in","r",stdin);
//freopen("outr.out","w",stdout);
while(scanf("%d",&m)==1 && m) {
scanf("%s",s);
n=strlen(s);

H
=0,xp[0]=1;
for(int i=n-1;i>=0;i--) H[i]=H[i+1]*x+s[i]-'a';
for(int i=1;i<=n;i++) xp[i]=xp[i-1]*x;

if(!can(1)) printf("none\n");
else {
int L=1,R=n+1;
while(L<R) {
int M=L+(R-L+1)/2;
if(can(M)) L=M;  else R=M-1;
}
can(L);
printf("%d %d\n",L,pos);
}
}
return 0;
}


hash
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: