求至少出现m次最长子串。
如果用后缀数组写,要二分长度,对sa[ ] 进行分组,看有没有一个组的元素个数不小于m 。
用哈希写, 同样是二分长度,代码量只有一半。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <set>
#include <hash_set>
using namespace std;
typedef unsigned long long uLL ;
const int maxn = 40050 ;
int pos ;
const uLL p = 9999997 ;
uLL powp[maxn] ;
uLL hash[maxn] ;
char s[maxn] ;
const int HashNum=1<<16;
struct HASH{
int flag[HashNum];
uLL has[HashNum];
void Init(){
memset(flag , 0 ,sizeof(flag)) ;
}
int Hash(uLL k)
{
int p=k%HashNum;
while(flag[p] && has[p]!=k)
p=(p+1)%HashNum;
return p ;
}
int Insert(uLL k){
int p=Hash(k);
has[p]=k;
return ++flag[p];
}
}hs ;
bool check(int l , int n , int m){
hs.Init();
bool ok = false ;
for(int i=1; i+l-1<=n; i++) {
uLL tmp = hash[i+l-1] - hash[i-1] * powp[l];
if( hs.Insert(tmp) >=m )
{pos = i ; ok = true ; }
}
return ok ;
}
int main()
{
powp[0] = 1 ;
for(int i=1; i<maxn; i++) powp[i] = powp[i-1] * p ;
int m ;
while(scanf("%d" ,&m)==1 && m){
scanf("%s" ,s+1) ;
int n = strlen(s+1) ;
hash[0] = hash[n+1] = 0 ;
for(int i=1; i<=n;i++) hash[i] = hash[i-1]*p + s[i] ;
int L = 0 , R = n ;
while(L<R) {
int mid = L + (R-L+1)/2 ;
if(check(mid , n ,m)) L = mid ;
else R = mid - 1 ;
}
if(!L) puts("none") ;
else printf("%d %d\n" , L , pos-1) ;
}
return 0;
}