NC5026E 相似的子串

NC5026E

題意

把原題意轉化爲給你一個長爲nn的字符串,求至少有kk個相同且不相交的長爲xx(可爲00)的子串,xmaxx_{max}爲多少?

思路

二分+哈希字符串 時間複雜度O(nlogn)O(nlogn)
這道題不要求得到所求子串爲什麼,而要求子串所能取得最大長度,且答案具有嚴格單調性,故可以二分答案。
那麼如何驗證?首先預處理字符串Hash得到
Hash數組表示對應的Hash值
power數組表示對應的baselengthibase^{length_i}
有一個難點在於如何保證不相交?

  • 我們在map的value中放入一個pair<int,int>,first放該字符串的結尾位置,second放該字符串的出現次數,當出現新的相同的hash值(相同的字符串)時我們驗證新的位置減去上一個的位置是否x\geq x,若滿足則更新最後一次出現且滿足的位置,並增加滿足的數量。

tips: unordered_mapunordered\_map查詢複雜度爲O(1)O(1)mapmap查詢複雜度爲O(logn)O(logn)
這裏用map我跑了一下沒掛,但是理論上來說是可以掛的。
上面是
上面是map 下面是unoreder_map

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const double eps = 1e-8;
const int NINF = 0xc0c0c0c0;
const int INF  = 0x3f3f3f3f;
const ll  mod  = 1e9 + 7;
const ll  maxn = 1e6 + 5;
const int N = 2e5 + 5;

int n,k;
char s[N];
unordered_map<unsigned long long,pair<int,int> > mp;
unsigned long long Hash[N],power[N],base=131;

bool check(int x){
	mp.clear();
	for(int i=x;i<=n;i++){
		unsigned long long h=Hash[i]-Hash[i-x]*power[x];
		if(i-mp[h].first>=x) mp[h].first=i,mp[h].second++;
		if(mp[h].second>=k) return true;
	}
	return false;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n>>k>>s+1;
	power[0]=1;
	for(int i=1;i<=n;i++){
		Hash[i] =Hash[i-1]*base+s[i]-'a'+1;
		power[i]=power[i-1]*base;
	}
	int L=0,R=n/k+1,ans=0;
	while(L<R){
		int mid=L+(R-L)/2;
		if(check(mid)) L=mid+1,ans=mid;
		else R=mid;
	}
	cout<<ans<<'\n';
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章