bitset复习

本文介绍了一种求解子集算术和的异或总和的高效算法。通过使用位运算和bitset优化传统DP方法,实现O(sum)的时间复杂度。文章提供了完整的C++代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目:求子集的算术和的异或和

题解:

按照正常思路是维护一个dp[i],表示和为i的组合有多少个,然后如果dp[i]%2==1则ans^i就可以了··然而复杂度为sum*n,果断T

考虑用一个布尔数组表示dp[i],dp[i]为1表示和为i的组合的数量为奇数,0为偶数

然后每输入一个数x,可以用dp[i]更新dp[i+x],即dp[i+x]=(dp[i+x]+dp[i])%2,既然我们用的是布尔数组,可以利用位运算+bitset,来一次性更新所有的i而不用一一枚举sum,即dp=dp^(dp<<x).


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
#include<bitset>
using namespace std;
const int N=2e6+5;
bitset<N>dp;
int ans=0,a,tot,n;
int main()
{
  //freopen("a.in","r",stdin);
  scanf("%d",&n);  
  dp[0]=1;
  for(int i=1;i<=n;i++)
  {
    scanf("%d",&a);
    tot+=a;dp^=(dp<<a);
  }
  for(int i=0;i<=tot;i++)
    if(dp[i])  ans^=i;
  cout<<ans<<endl;
  return 0;
}

### BitSet 的用途 BitSet 是一种用于表示位向量(bit vector)的数据结构,广泛应用于需要高效处理大量布尔状态的场景。它允许通过索引访问和操作单个位(bit),每个位的状态可以是 `true`(1)或 `false`(0)。BitSet 的主要用途包括但不限于以下几种: - **快速查找某个数据是否在一个集合中**:由于每个位可以代表一个元素的存在与否,因此 Bitset 常用于存在性检查,例如判断一个整数是否存在于某个范围内[^2]。 - **排序与去重**:通过将数值映射到位的位置,可以在遍历 Bitset 时按顺序输出已存在的元素,实现高效的排序和去重操作。 - **集合运算**:支持逻辑与、逻辑或、逻辑异或等操作,可以用来计算两个集合的交集、并集和差集等[^1]。 - **操作系统中的资源管理**:例如在文件系统中用于磁盘块的标记,标识哪些块已被使用,哪些块仍为空闲[^2]。 ### BitSet 的实现方法 Java 中的 `BitSet` 类通过内部维护一个 `long[]` 数组来存储位信息。数组的大小会根据需求动态增长,并且为了提高性能和简化处理逻辑,其大小通常是 64 的倍数。这意味着如果初始化的位数不是 64 的整数倍,则会向上取整到最近的 64 的倍数,从而保证内存对齐并减少边界情况的处理[^3]。 #### 初始化与扩展 当创建一个 `BitSet` 实例时,可以通过指定初始大小来预分配空间。例如: ```java BitSet bitSet = new BitSet(128); ``` 此时,如果初始大小为 128 位,则内部数组将被初始化为包含两个 `long` 元素(每个 `long` 占用 64 位)。随着更多位被设置,数组会自动扩展以容纳新的位。 #### 设置与清除位 通过 `set(int bitIndex)` 方法可以将指定索引位置的位设为 `true`,而 `clear(int bitIndex)` 则将其设为 `false`。这些操作基于位移和掩码机制完成。例如,给定一个 `bitIndex`,实际操作可能涉及如下位运算: ```java words[wordIndex] |= (1L << bitIndex); ``` 其中 `wordIndex` 表示该位在对应 `long` 元素中的偏移量,`1L << bitIndex` 构造了一个只有一位为 1 的掩码,通过按位或操作更新目标位的状态[^4]。 #### 查询位状态 使用 `get(int bitIndex)` 方法可以获取指定索引位置的位值。此方法返回一个布尔值,表示该位是否被设置为 `true`。 #### 集合操作 `BitSet` 提供了多种集合操作方法,如: - `and(BitSet set)`:执行按位与操作,保留两个 Bitset 中共同为真的位。 - `or(BitSet set)`:执行按位或操作,合并两个 Bitset 中所有为真的位。 - `xor(BitSet set)`:执行按位异或操作,仅保留两个 Bitset 中互不相同的位。 这些操作通常直接作用于底层的 `long[]` 数组,逐字进行位运算,效率较高。 #### 性能优化 除了基本的操作外,`BitSet` 还提供了 `length()` 和 `size()` 等方法,分别用于获取最高位为真的索引加一以及整个 Bitset 所占用的位数。此外,`isEmpty()` 可以快速判断是否有任何位被设置为 `true`。 ### 示例代码 以下是一个简单的 Java BitSet 使用示例,展示了如何记录字符串中出现过的字符: ```java import java.util.BitSet; public class WhichChars { private BitSet used = new BitSet(); public WhichChars(String str) { for (int i = 0; i < str.length(); i++) { used.set(str.charAt(i)); // 将字符对应的位设置为 true } } public void printUniqueChars() { for (int i = 0; i < used.size(); i++) { if (used.get(i)) { System.out.print((char) i + " "); } } System.out.println(); } public static void main(String[] args) { WhichChars wc = new WhichChars("hello world"); wc.printUniqueChars(); // 输出: h e l o w r d } } ``` 此程序利用 `BitSet` 记录输入字符串中出现的所有字符,并最终打印出所有唯一字符。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值