题目:
大致翻译:
在字符串s中寻找出现次数不小于m的最长子串,输出该子串的长度和在s中最后一次出现的位置。
思路:
运用二分的思想来查找子串的长度,相同长度子串运用哈希存入map中,map统计子串出现次数是否不小于m
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define pa pair<ull,ull>
//const ull mod=1e9+7;
const int N =1e5+7;
const int p=131;
const ull mod1=1e9+7,mod2=2147483647;
ull a1[N],h1[N];
map<ull,int>mp;
int n;
void hash1(string sa){//预处理hash函数前缀和
a1[0]=1;
for(int i=1;i<=sa.size();i++){//注意等于号
a1[i]=a1[i-1]*p%mod1;
h1[i]=(h1[i-1]*p%mod1+(sa[i-1]-'a'+1))%mod1;
}
}
ull get1(int l,int r){//计算s[l--r]的hash值
return (h1[r]-h1[l-1]*a1[r-l+1]%mod1+mod1)%mod1;
}
int find(int len,string s){
mp.clear();
int pos=-1;
// cout<<"len="<<len<<endl;
for(int i=1;i+len-1<=s.size();i++){//注意等于号
ull num=get1(i,i+len-1);//s[l--r]的hash值
mp[num]++;
// cout<<"num="<<num<<"mp="<<mp[num]<<endl;
if(mp[num]>=n){//每次不小于n都记录位置,寻找最后一次出现的位置
pos=i;
// cout<<"pos="<<pos<<endl;
}
}
return pos;
}
int main(){
string s;
int ans,pos;//记录位置
while(cin>>n&&n){
cin>>s;
hash1(s);
if(find(1,s)==-1){//当长度为1时都无法不小于n说明不可能符合题意
cout<<"none"<<endl;
continue;
}
int l=1,r=s.size()-n+1,len=0;
while(l<=r){//二分长度
int mid=l+r>>1;
pos=find(mid,s);
if(pos==-1){
r=mid-1;
}else{
l=mid+1;
ans=pos;
len=max(mid,len);//更新答案
// cout<<"mid="<<mid<<"ans="<<ans<<endl;
}
// cout<<"l="<<l<<" r="<<r<<endl;
}
cout<<len<<" "<<ans-1<<endl;
}
return 0;
}