题目:
在一个字符串中,找出出现次数不小于m次的最长的子串。
输出最长的子串长度和最右边一个子串的起始位置。
分析:
字符串hash可做。
二分子串的长度,然后处理出来所有这个长度的子串的值,排序后找有没有相同的大于等于m个即可。
代码:
#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <vector>
#include <set>
#include <map>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
#define ms(a,b) memset(a,b,sizeof(a))
typedef long long ll;
typedef unsigned long long ull;
const int MAXN=4e4+5;
const double EPS=1e-8;
const int INF=0x3f3f3f3f;
const int base = 163;
char s[MAXN];
int n,m,pos;
ull Hash[MAXN],p[MAXN];
typedef struct{
ull x;
int ps;
}S;
S tmp[MAXN];
void makeHash(){
Hash[0] = 0;
p[0] = 1;
for(int i=1;i<=MAXN;i++){
p[i] = p[i-1] * base;
}
for(int i=1;i<=n;i++){
Hash[i] = Hash[i-1] * base + s[i]-'a';
}
}
ull getHash(int l,int r,ull Hash[]){
return Hash[r] - Hash[l-1] * p[r-l+1];
}
bool cmp(const S a,const S b){
if(a.x != b.x) return a.x < b.x;
return a.ps < b.ps;
}
bool ok(int len){
pos = -1;
int k=0;
for(int i=n-len+1;i>=1;i--){
tmp[k].x = getHash(i,i+len-1,Hash);
tmp[k++].ps = i;
}
sort(tmp,tmp+k,cmp);
int cnt = 1;
if(m==1) pos = 1;
for(int i=1;i<k;i++){
if(tmp[i].x == tmp[i-1].x){
cnt ++;
if(cnt >= m){
pos = max(pos,tmp[i].ps);
}
}else{
cnt = 1;
}
}
return pos != -1;
}
int main(){
while(scanf("%d",&m)){
if(m==0) break;
scanf("%s",s+1);
n = strlen(s+1);
makeHash();
int l=1,r=n,ans=-1,ansp;
pos=-1;
while(l<=r){
int mid = (l+r)/2;
if(ok(mid)){
ans = mid;
ansp = pos;
l = mid + 1;
}else{
r = mid - 1;
}
}
if(ans == -1){
printf("none\n");
}else{
printf("%d %d\n",ans,ansp-1);
}
}
return 0;
}