首页 > 其他分享 >bitset专题

bitset专题

时间:2024-05-18 16:11:07浏览次数:24  
标签:专题 int pos cin solve bitset dp

bitset

bitset前身:普通状态压缩的优化

以cf937G为例,对于邻接矩阵的由二维压缩到一维

#include <bits/stdc++.h>

using i64 = long long;

void solve() {
    int n;
    std::cin >> n;
    
    std::vector<std::string> g(n), w(n);
    for (int i = 0; i < n; i++) {
        std::cin >> g[i] >> w[i];
    }
    
    std::vector<int> e(n);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            if (g[i] == g[j] || w[i] == w[j]) {
                e[i] |= 1 << j;
            }
        }
    }
    
    std::vector<int> dp(1 << n);
    for (int x = 0; x < n; x++) {
        dp[1 << x] |= 1 << x;
    }
    
    int ans = 0;
    for (int s = 1; s < (1 << n); s++) {
        if (dp[s]) {
            ans = std::max(ans, __builtin_popcount(s));
        }
        for (int y = 0; y < n; y++) {
            if ((~s >> y & 1) && (dp[s] & e[y])) {
                dp[s | 1 << y] |= 1 << y;
            }
        }
    }
    std::cout << n - ans << "\n";
}

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    
    int t;
    std::cin >> t;
    
    while (t--) {
        solve();
    }
    
    return 0;
}

floyd求可达性传递闭包

Solution:初步做法:首先本题只需要求所有偏序关系,考虑建图的时候只建单向图。朴素floyd是\(O(n^3)\)的本题n是1e3显然无法通过,考虑过程中我们只需要维护01的信息,我们考虑使用bitset的过程将与的过程优化\(O(\frac {n}{w})(w=64)\)

//floyd计算,优化64常数判断,bitset优化可达性邻接矩阵
//需要保证任意两点相互可达,
bitset<N>dp[N];
void solve(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v;cin>>u>>v;
		dp[u][v]=1;
	}
	//注意枚举顺序,先枚举中转点i
	for(int k=1;k<=n;k++){
		//枚举起点
		for(int i=1;i<=n;i++){
			//k能到的,i也能到
			if(dp[i][k])dp[i]|=dp[k];
		}
	}
	int ans=0;
	for(int i=1;i<=n;i++)ans+=dp[i].count();
	ans=n*(n-1)/2-ans;
	cout<<ans<<endl;
}

听dmy学习记录

常用位运算函数

ll n=(1LL<<40)-1LL;
	cout<<__builtin_popcountll(n)<<endl;//二进制里1的个数
	//40
	cout<<__lg(n)<<endl;//等价于 31-__builtin_clz(n);
	//39
	
	
	
	cout<<63-__builtin_clzll(n)<<endl;//最高位开始连续0的个数
	//39
	
	cout<<__builtin_ctz(8)<<endl;//最低位开始连续0的个数
	//3
	
	bitset<5>B=21;
	cout<<B<<endl;
for(int i = (int)(B._Find_first()); i != B.size();i = (int)(B._Find_next(i)))
    cout << i << " ";
    //找到所有含1的位置
    
   // 10101
//    0 2 4 

bzoj3687https://hydro.ac/d/bzoj/p/3687

题意:求所有子集和的异或和

Solution:首先我们不可能枚举所有子集,所以我们只能考虑dp。\(dp[i][j]\)考虑前i个数,子集和为j的方案,考虑最后需要全部异或起来,偶数方案数直接抵消

因此只需要维护奇偶性,所以我们考虑背包运算中异或,但是现在值域总和2e6,1000个数,显然过不去

考虑bitset优化背包,可达性01用的。由于本题只需要看%2的情况,所以同理也可以使用。时间复杂度:\(O(nm/w)\)

bitset<M>b;
void solve(){
	cin>>n;
	b[0]=1;
	for(int i=1;i<=n;i++){
		int x;cin>>x;
		b^=(b<<x);
		//cerr<<b<<endl;
	}
	ll ans=0;
	for(int i=1;i<=1000000;i++){
		if(b[i])ans^=i;
	}
	cout<<ans<<endl;
}

SDUT2023校赛https://acm.sdut.edu.cn/onlinejudge3/contests/4098/problems/O

题意:给定一个集合1-n。求所有子集和的乘积.(n<=200)

Solution:考虑值域和数据个数,可以直接dp。\(dp[i][j]\)表示考虑前i个数,和为j的方案数。假设先不取模,我们继续考虑下去。最后统计答案的时候的每次算乘积算的是\(i^{dp[i]}\)。!注意注意注意。dp数组是作为指数出现的,所以我们不能直接对其mod取模。考虑费马小定理,这种指数乘积在mod是质数的时候是以mod-1为周期的,所以我们dp的时候应当对mod-1取模。

int dp[N*N];[j]
int qmi(int a,int b){
	//cerr<<a<<" "<<b<<" ";
	int res=1LL;
	while(b){
		if(b&1)res=(res*a)%mod;
		a=a*a%mod;
		b>>=1;
	}
	//cerr<<res<<endl;
	return res;
	
}
//相当于对cnt次数取模了,这是对指数取模,是不合法的、
//考虑费马小定理每p-1个数为1
void solve(){
	cin>>n;
	dp[0]=1;
	for(int i=1;i<=n;i++){
		for(int j=n*(n+1)/2;j>=i;j--){
			dp[j]+=dp[j-i];dp[j]%=(mod-1);
		}
	}
	int ans=1LL;
	for(int i=1;i<=n*(n+1)/2;i++)
	{
		int cnt=dp[i];
		//cerr<<i<<" "<<dp[i]<<endl;
		ans*=qmi(i,cnt);ans%=mod;
	}
	cout<<ans<<endl;
}

DAG计数:\(O(n^{2}/w)\)的解法

题意:有向无环图,输入都是小向大连边,求出每个点能到达多少点?

Solution:考虑如果u到v有边,那么v所能到达的点u也能到达,直接利用bitset的或运算就可以完成。f[u]|=f[v]

检查时间:50000*50000/64=4e7

计算空间:50000*50000/8/1024/1024=298MB(bit->byte->kb->MB)

bitset<N>f[N];
vector<int>e[N];
/*debug
5 0000100000 
4 0000010000 
3 0000101000 
2 0000101100 
1 0000111110 

input
5 5
1 2
1 4
2 3
2 5
3 5

out
5
3
2
1
1
*/
void solve(){
	cin>>n;cin>>m;
	for(int i=1;i<=m;i++){
		int u,v;cin>>u>>v;
		e[u].push_back(v);
	}
	//逆序就是拓扑序
	for(int i=n;i>=1;i--){
		f[i][i]=1;
		for(auto v:e[i]){f[i]|=f[v];}
		cerr<<i<<" "<<f[i]<<endl;
	}
	for(int i=1;i<=n;i++)cout<<f[i].count()<<endl;
}

bitset还可以解决解决三元环计数,求传递闭包。思路都是枚举两个点,将枚举第三点的耗时从\(O(n)\)优化成\(O(n/w)\)。

三元环计数详情见该专题

bitset解决动态带修字符串匹配

https://hydro.ac/d/bzoj/p/4503 带通配符的字符串匹配

题意:给长串s,模式串t,t中含有?作为通配符,求s中t出现了几次,分别在哪开始?

Sol:考虑有通配符不好用kmp做,有FFT做法,待补。利用bitset的思想是维护s中每个位置作为起点是否可行。对于t中字母 t[j],对于s中所有不为这个字母的位置i,则i-j一定无法作为起点,我们利用bitset可以对于每个j花费\(O(n/w)\)的时间完成这个处理。

实现:提前开26个bitset预处理每个字母在s的哪些位置出现过。每次遇到一个 t[j]就右移j位对应bitset

bitset<N>b[28];
bitset<N>ans;
void solve(){
	string s,t;cin>>s>>t;
	n=s.size();m=t.size();
	for(int i=0;i+m-1<n;i++)ans[i]=1;
	for(int i=0;i<n;i++)b[s[i]-'a'][i]=1;
	for(int i=0;i<m;i++){
		if(t[i]=='?')continue;
		ans&=b[t[i]-'a']>>i;
	}
	cout<<ans.count()<<endl;
	for(int i=0;i+m-1<n;i++){
		if(ans[i]==1)cout<<i<<endl;
	}
}

多次区间查询给出原串,模式串保持不变,且动态带修。http://codeforces.com/problemset/problem/914/F

给你一个字符串 \(s\),共有 \(q\) 次操作,每个都是下面两种形式的一种。

  • 1 i c:将字符串 \(s\) 的第 \(i\) 项变为字符 \(c\)。

  • 2 l r y:求字符串 \(y\) 在字符串 \(s\) 中以第 \(l\) 项为起点,以第 \(r\) 项为终点的子串(第 \(l\) 和第 \(r\) 项)中作为子串出现的次数。

\(1\leq |s|\leq 10^5\),\(1\leq q\leq 10^5\),\(\sum |y| \leq 10^5\)。

Sol:考虑对于区间查询转化为后缀查询,利用bitset的移位性质,先得到L-n的子串个数,再得到r+1-n的子串个数,做差即可。我们考虑依旧采用上面的思想,维护每个字符的出现位置。利用模式串不断筛选可用的起点,最后为1的位置就是可用的起点。

时间复杂度:\(O(nm/w)\)

bitset<N>b[28];
bitset<N>ans;
void solve(){
	string s;cin>>s;
	int len=s.size();
	for(int i=0;i<len;i++)b[s[i]-'a'][i]=1;
	cin>>m;
	for(int i=1;i<=m;i++)
	{
		int op;cin>>op;
		if(op==1){
			int pos;cin>>pos;pos--;
			char c;cin>>c;
			b[s[pos]-'a'][pos]=0;
			s[pos]=c;
			b[s[pos]-'a'][pos]=1;
		}
		else {
			int l,r;cin>>l>>r;l--;r--;
			ans.set();
			string t;cin>>t;n=t.size();
			if(r-l+1<n){
				cout<<0<<endl;
				continue;
			}
			for(int i=0;i<n;i++){
				ans&=b[t[i]-'a']>>i;		
			}
			int cl=(ans>>l).count(),cr=(ans>>(r+2-n)).count();
			cout<<cl-cr<<endl;
			
		}
	}
}

根号分治bitset+滑动窗口http://codeforces.com/problemset/problem/963/D

给你一个字符串 \(s \pod {|S| \le 10^5}\) ,有 \(n \pod {n \le 10^5}\) 个询问,第 \(i\) 个询问包含一个整数 \(k_i\) 和一个字符串 \(m_i \pod {\sum_i |m_i| \le 10^5}\) 。要求找到一个字符串 \(t\) ,使得 \(t\) 是 \(s\) 的子串并且 \(m_i\) 至少在 \(t\) 中出现了 \(k_i\) 次。你只需要求出 \(t\) 的最短长度。
保证 \(m_i\) 互不相同。

CF963D Frequency of String 题解 - 洛谷专栏 (luogu.com.cn)

Sol:首先考虑对于每个模式串预处理出在远传s中所有可行的endpos,处理手法与上面一样,上面预处理的起点,这里用终点,为了不糊涂改用1_index了,本质一样。我们考虑统计答案的复杂度,直接一想似乎是\(O(nm)\)的无法通过,但注意到题目说每个模式串不同,且总长度不超过1e5,经典根号分治,不同长度的串一定不超过\(\sqrt{\sum{|t_i|}}\),对于固定长度的串可行endpos的个数是线性的,所以统计答案复杂度是\(O(n\sqrt{n}/w)\)

预处理: 100000*100000/64=1.5e8

bitset<N>b[28];
bitset<N>ans;
void solve(){
	cin>>s;n=s.size();
	s=" "+s;
	for(int i=1;i<=n;i++)b[s[i]-'a'][i]=1;
	int q;cin>>q;
	for(int i=1;i<=q;i++){
		int k;cin>>k;
		ans.set();
		vector<int>v;
		string t;cin>>t;
		m=t.size();t=" "+t;
		for(int i=1;i<=m;i++){
			ans&=b[t[i]-'a']<<(m-i);
			//左移m-1位的时候。ans前面的不合法低位就变为0了
            //左移1的时候,ans高位不合法的就没了
		}
for(int pos=ans._Find_first();pos!=N;pos=ans._Find_next(pos)) v.push_back(pos);
int res=inf;
for(int i=k-1;i<v.size();i++){
	
	//l=r1-m+1
	//r=r2
	//len=r-l+1=r2-r1+m
	res=min(res,m+v[i]-v[i-k+1]);
}
if(res==inf)cout<<-1<<endl;
else cout<<res<<endl;
	}
}

总结:对于以上字符串匹配需要注意的细节:下标移动和边界的计算(可以设未知数)。不合法情况导致越界需要提前特判退出。最后一题那个找1的上界没想清楚

bitset配合莫队在数据结构方面的应用

标签:专题,int,pos,cin,solve,bitset,dp
From: https://www.cnblogs.com/mathiter/p/18199406

相关文章

  • 倍增专题
    倍增大专题[AHOI2008]紧急集合/聚会-洛谷题意:给定一棵树,多次查询费马点(bushi费马点的含义是:到三个点的距离之和最小Solution:考虑画图发现树上三点两两求lca,必然至少两个相同,然后我们只需要让费马点为另一个点就可以了,因为这一段路程只需要一个点走就最好了。//考虑到让......
  • Celery专题
    Celery专题【一】Celery介绍【二】Celery快速使用【三】Celery包结构【四】django中使用celery【五】使用django_celery_beat在admin后台配置计划任务【六】Celeryadmin监视任务【七】Flower监控celery任务【八】任务异常自动告警......
  • 【专题】2024小红书餐饮行业方法论报告合集PDF分享(附原数据表)
    原文链接:https://tecdat.cn/?p=36199原文出处:拓端数据部落公众号报告合集显示,消费者对餐饮的需求正从单一的口味体验转变为追求更高层次的情绪价值和文化价值。餐饮不仅是生活的小确幸,更成为社交、休闲和探索的重要场景。小红书凭借其真实、利他、生动、丰富的内容,成为餐饮消费......
  • 【专题】2024年中国即时配送行业研究报告合集PDF分享(附原数据表)
    原文链接:https://tecdat.cn/?p=36188原文出处:拓端数据部落公众号即时配送服务凭借其无与伦比的高效与便捷,已深深满足了当代社会对于速度和便捷性的双重追求。据权威报告揭示,即时配送行业规模已突破3400亿元,且预测至2028年,这一数值将飙升至超过8100亿元。阅读原文,获取专题报告合......
  • 【专题】2023年中国白酒行业消费白皮书报告PDF合集分享(附原数据表)
    原文链接:https://tecdat.cn/?p=34188原文出处:拓端数据部落公众号2023年中国白酒行业消费白皮书报告合集,总结了消费市场的两大传承和五大进化,以帮助白酒企业更好地理解消费者心理和供需变化,从而把握增长机会。两大传承包括争夺消费者的“第一口酒”以及品牌在消费决策中的关键作......
  • 当实时互动遇上新硬件:GIAC 全球互联网架构大会「新硬件」专题论坛
    今年,被广泛预见为AI技术关键转折点的年份,生成式AI热度不断攀升,应用落地加速深化。在这个过程中,为了适应日益复杂的业务需求,背后的架构也将迎来新一轮的革新。 而在这场技术变革的浪潮中,GIAC全球互联网架构大会无疑成为了引领风潮的灯塔。作为深圳乃至华南地区技术领导者和......
  • Go语言高并发与微服务实战专题精讲——远程过程调用 RPC——高性能的 gRPC
    远程过程调用RPC——高性能的gRPC gRPC,这一由Google推出的高性能、开源、通用RPC框架,凭借其众多引人注目的特性,已成为业界瞩目的焦点。它基于HTTP/2协议标准设计开发,并采用ProtocolBuffers作为默认的数据序列化协议,广泛支持多种编程语言。gRPC不仅简化了服务的精确定义,而且......
  • 【专题】2024中国医疗器械企业全球化发展报告合集PDF分享(附原数据表)
    原文链接:https://tecdat.cn/?p=36180原文出处:拓端数据部落公众号中国医疗器械企业在国内市场面临同质化竞争和研发能力薄弱等挑战,而海外市场则展现出巨大的增长潜力和性价比优势。因此,全球化布局对于中国医疗器械企业至关重要。该报告合集详细分析了这些市场的宏观经济、医疗体......
  • 中电金信:专题报告·商业银行对公数字化转型体系架构及实践拆解
    当今,数字化转型已然成为商业银行发展的关键动力,在这个数字时代,对公业务数字化转型更是势在必行。 基于此,中电金信发布《商业银行对公数字化转型专题报告》(简称《报告》),针对对公数字化转型进行了专题研究。报告对主要商业银行对公数字化转型进行了深入的业务调研和分析总结,从对......
  • 【专题】2022年智能汽车行业数字化人才白皮书报告PDF合集分享(附原数据表)
    原文链接:https://tecdat.cn/?p=34111随着新一轮技术革命和产业变革的推动,以及国家政策的大力扶持,电动化、智能化、网联化已经成为汽车行业发展的新趋势。在这种背景下,各大企业纷纷争夺数字化人才,以推动产品的规模化落地和商业化创新应用。阅读原文,获取专题报告合集全文,解锁文末53......