bitset(hdu 6085)

本文介绍了一种针对数组余数查询的优化算法,通过预处理实现快速查询ai%bi等于特定值k的元素数量的奇偶性。利用bitset进行高效存储与计算,特别适用于大数据集下的快速响应。

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

题意:给定两个数组a和b然后q次询问,输出ai%bi==k的个数的奇偶性。
思路:可以转化为给a数组每个都减去k求(ai-k)%bi==0的有多少个,又因为只有当bi>k时才会有结果所以可以预处理处所有的答案为k的结果最后O(1)输出就好了。枚举k然后从大到小枚举bi每次都将bi的倍数统计出来
然后每次就可以算出(ai-k)%bi==0的有多少个了,具体的看代码和注释。
这里有一个关于bitset的用法及函数

#include<cstdio>
#include<cstring>
#include<bitset>
#include<iostream>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1e6+10;
bitset<50010> a,b,ans,bx;
void solve(int tmp)
{
    for(int i=tmp;i>=0;i--)//枚举k
    {
        ans[i]=(bx&(a>>i)).count()&1;
        /*
        ans[i]存的是a[j]%b[j]==i的有多少个的奇偶性
        bx[i]里面是i%b[j]==0的奇偶性
        a>>i相当于将所有的ai的值都减了i丢掉了<0的值
        &1是判断奇偶性的
        判断的是(ai-k)%bj==0的有多少个bj要>k所以从大到小遍历
        这样每次更新就可以计算后面的值了
        */
        if(!b[i]) continue;
        for(int j=0;j<50010;j+=i)//当b中有i这个值时则i就会对后面判断有影响
            bx.flip(j);
    }
}
int main()
{
    int ncase;
    scanf("%d",&ncase);
    while(ncase--)
    {
        a.reset();
        b.reset();
        ans.reset();
        bx.reset();
        int n,m,q;
        scanf("%d%d%d",&n,&m,&q);
        for(int i=0;i<n;i++)
        {
            int x;
            scanf("%d",&x);
            a.set(x);
        }
        int tmp=0;
        for(int j=0;j<m;j++)
        {
            int x;
            scanf("%d",&x);
            b.set(x);
            tmp=max(tmp,x);//计算k最大值可以是多少
        }
        solve(tmp);
        while(q--)
        {
            int x;
            scanf("%d",&x);
            printf("%d\n",ans[x]?1: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、付费专栏及课程。

余额充值