题意:题意:给你一个串,问期中至少出现m次的最长子串及其最大的起始位置坐标。
数据范围: |s|<=4e4
题解:Hash+Lcp+二分
二分枚举答案,计算字符串的hsah值,然后根据条件判断,最后找到最大的起始位置就可以
这里比较可以优化,如果是朴素的比较方法,O(n^n)
可以先排序,只要进行O(n)的查找
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <algorithm>
#define ull unsigned long long
using namespace std;
const int maxn=4e4+100;
char s[maxn];
const ull base=163;
ull Hash[maxn],p[maxn],res[maxn];
int Rank[maxn];
int m,len,pos;
bool cmp(int x,int y)
{
return res[x]<res[y]||(res[x]==res[y]&&x<y);
}
bool solve(int L)
{
pos=-1;
for(int i=1; i<=len-L+1; ++i)
{
Rank[i]=i;
res[i]=Hash[i]-Hash[i+L]*p[L];
}
sort(Rank+1,Rank+len-L+1+1,cmp);
int cnt=0;
for(int i=1; i<=len-L+1; ++i)
{
if(i==1||res[Rank[i]]!=res[Rank[i-1]]) cnt=0;
if(++cnt>=m) pos=max(pos,Rank[i]);
}
return pos>0;
}
int main()
{
p[0]=1;
for(int i=1; i<maxn; ++i) p[i]=p[i-1]*base;
while(scanf("%d",&m)&&m)
{
scanf("%s",s+1);
len=strlen(s+1);
Hash[len+1]=0;
for(int i=len; i>=1; --i)
Hash[i]=Hash[i+1]*base+s[i]-'a';
int l=1,r=len,mid,ans=0;
while(l<=r)
{
mid=(l+r)>>1;
if(solve(mid))
{
ans=mid;
l=mid+1;
}
else r=mid-1;
}
if(ans<1) puts("none");
else
{
solve(ans);
printf("%d %d\n",ans,pos-1);
for(int i=pos; i<=pos+ans-1; ++i)
printf("%c",s[i]);
printf("\n");
}
}
return 0;
}