题目地址:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3358
思路:
为每个后缀计算一个哈希值,满足H(i)=H(i+1)x+s[i] (其中0<=i<n , H(n)=0)
对于一段长为L的字符串s[i]---s[i+L-1],定义它的哈希值Hash(i,L)=H(i)-H(i+L)x^L。
当预处理H和x^L之后,Hash(i,L)可以在常数时间内算出。一般将其存在unsigned long long里,在算术运算中自然溢出,相当于模2^64。
对于一子串,长度越长其可能出现的次数越少,则二分长度L,判断当前长度下是否有串出现的次数不小于m:将L下的Hash值从小到大排序,若某个值出现超过m次,即存在该串。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define debu
using namespace std;
const int maxn=40000+50;
typedef unsigned long long ULL;
const int p=233;
struct Node
{
ULL Hash;
int id;
};
int len,m,ansPos;
Node tmp[maxn];
ULL preHash[maxn],mul[maxn];
char st[maxn];
void init()
{
mul[0]=1;
for(int i=1; i<maxn; i++)
{
mul[i]=mul[i-1]*p;
}
}
void getHash()
{
preHash[len]=0;
for(int i=len-1; i>=0; i--) preHash[i]=preHash[i+1]*p+(st[i]-'a');
}
int cmp(Node a,Node b)
{
if(a.Hash==b.Hash) return a.id<b.id;
else return a.Hash<b.Hash;
}
int getAppear(int l)
{
int flag=0,num=0,pos=-1;
for(int i=0;i<len-l+1;i++)
{
tmp[i].id=i;
tmp[i].Hash=preHash[i]-preHash[i+l]*mul[l];
}
sort(tmp,tmp+len-l+1,cmp);
for(int i=0;i<len-l+1;i++)
{
if(i==0||tmp[i].Hash!=tmp[i-1].Hash) num=0;
num++;
if(num>=m)
{
flag=1;
pos=max(pos,tmp[i].id);
}
}
if(!flag) return 0;
else
{
ansPos=pos;
return 1;
}
}
void solve()
{
int ans=-1;
if(!getAppear(1))
{
printf("none\n");
return ;
}
int l=1,r=len;
while(l<=r)
{
int mid=(l+r)>>1;
if(getAppear(mid))
{
l=mid+1;
ans=mid;
}
else
{
r=mid-1;
}
}
getAppear(ans);
printf("%d %d\n",ans,ansPos);
}
int main()
{
#ifdef debug
freopen("in.txt","r",stdin);
#endif // debug
init();
while(scanf("%d",&m)!=EOF&&m)
{
scanf("%s",st);
len=strlen(st);
getHash();
solve();
}
return 0;
}