ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

bitset 的妙用:乱搞字符串匹配

2021-03-07 20:35:36  阅读:228  来源: 互联网

标签:count 妙用 结束 int 位置 乱搞 bitset 带修


最近碰到了几次 bitset 乱搞字符串匹配的情况,故写文以记之。

1. 算法简介

核心思想:假设文本串为 \(s\),则对字符集中的每一个字符 \(c\) 开一个大小为 \(|s|\) 的 bitset \(N_c\),记录 \(c\) 出现在 \(s\) 中的哪些位置。

用多个模式串 \(t\) 去匹配 \(s\),并且求出 \(t\) 在 \(s\) 中每一次出现的结束位置,那么有这样一个套路:开一个长度为 \(|s|\) 的 bitset \(M\) 作为答案,一开始每一位都为 \(1\)。\(M\) 的含义:所有为 \(1\) 的位为可能的结束位置。遍历 \(t\) 中的每一个字符 \(t_i\),并将 \(N_{t_i}\) 左移(数位从小到大是从右往左,而位置是从左到右,注意区分) \(|t|-i\) 位的结果 \(N'_{t_i}\) 按位与 \(M\),即 \(M\gets M\ \mathrm{bitand}\ N’_{t_i}\)。最后得到的 \(M\) 即为 \(t\) 在 \(s\) 中所有出现的结束位置。总的时间复杂度为 \(\mathcal{O}(\frac{|s|\sum|t|}{\omega})\)。

这实际上就是将暴力匹配用 bitset 优化了一下。对于 \(t_i\) 考虑对可能的结束位置的限制:只有 \(t_i\) 在 \(s\) 中的所有出现位置向右移动 \(|t|-i\) 位后的所有位置,才可能成为 \(t\) 最终的结束位置。而将所有限制合起来就可以得到最终的结束位置。

废话不多说,来两道例题感受一下 bitset 的神奇之处。

2. 例题

I. CF914F Substrings in a String

题意简述:给出文本串 \(s\),多次询问 \(l,r,y\) 求 \(y\) 在 \(s[l:r]\) 中出现了多少次。带修。

太经典了。

注意到这个带修就和恶心,普通的 SAM 做不起来。接下来有两个选择:

  1. 巨大多难写的分块 SAM。
  2. 注意到时限竟然有 6s,而数据范围只有 \(10^5\),于是 bitset 暴力硬莽就完事了嗷!!!!11

具体实现方法和上题几乎一模一样,带修直接修改 bitset,查询的时候将 \(M\) 分别右移 \(l+|y|-2\) 位和 \(r\) 位,使用类似前缀和的思想去掉区间带来的影响(即计算 \([l+|y|-1,n]\) 与 \([r+1,n]\) 的贡献差)。计算得到的两个 bitset 分别有多少 1,作差,再与 \(0\) 取最大值即可(因为 \(l+|y|-2\) 可能大于 \(r\),而 bitset 的 count 应该是 unsigned int,老坑了)。

#include <bits/stdc++.h>
using namespace std;

const int N=1e5;
const int S=26;

int n,q,len,tp,l,r;
char s[N],t[N],ch;
bitset <N> c[S],ans;

int main(){
	scanf("%s%d",s,&q),n=strlen(s);
	for(int i=0;i<n;i++)c[s[i]-'a'][i]=1;
	while(q--){
		scanf("%d%d",&tp,&l),l--;
		if(tp==1)scanf("%s",&ch),c[s[l]-'a'][l]=0,c[(s[l]=ch)-'a'][l]=1;
		else{
			scanf("%d%s",&r,t),len=strlen(t),ans.set();
			for(int i=0;i<len;i++)ans&=c[t[i]-'a']<<len-i-1;
			cout<<max(0,(int)((ans>>l+len-1).count()-(ans>>r).count()))<<"\n";
		}
	}
	return 0;
}

标签:count,妙用,结束,int,位置,乱搞,bitset,带修
来源: https://www.cnblogs.com/alex-wei/p/bitset_yyds.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有