NC5026E 相似的子串

9 篇文章 0 订阅
1 篇文章 0 订阅

NC5026E

题意

把原题意转化为给你一个长为 n n n的字符串,求至少有 k k k个相同且不相交的长为 x x x(可为 0 0 0)的子串, x m a x x_{max} xmax为多少?

思路

二分+哈希字符串 时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)
这道题不要求得到所求子串为什么,而要求子串所能取得最大长度,且答案具有严格单调性,故可以二分答案。
那么如何验证?首先预处理字符串Hash得到
Hash数组表示对应的Hash值
power数组表示对应的 b a s e l e n g t h i base^{length_i} baselengthi
有一个难点在于如何保证不相交?

  • 我们在map的value中放入一个pair<int,int>,first放该字符串的结尾位置,second放该字符串的出现次数,当出现新的相同的hash值(相同的字符串)时我们验证新的位置减去上一个的位置是否 ≥ x \geq x x,若满足则更新最后一次出现且满足的位置,并增加满足的数量。

tips: u n o r d e r e d _ m a p unordered\_map unordered_map查询复杂度为 O ( 1 ) O(1) O(1) m a p map map查询复杂度为 O ( l o g n ) 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值