学会用bitset乱搞

bitset的基本用法

介绍

bitset 是一个存储 \(0/1\) 的容器,但是它的储存是以 bit 为单位的,内存仅为一个 \(bool\) 类型变量的 \(\frac{1}{8}\) ,因此其时空间复杂度都很优秀

要想使用 bitset ,首先需要引用头文件 #include<bitset>

bitset 模板类的定义为:

template <size_t N>
class bitset
{
    ...
};

其中 size_t N 是无符号整型,在使用时 N 必须为一个整型常数

bitset<10>s 举例,这是一个由 \(10\)\(0/1\) 组成的容器,下标从 \(0\) 开始,最低位在最右端

声明

常见有三种声明方式

  1. bitset<10> s;//bitset()
    cout << s << endl;//0000000000
    

    当这种情况时, bitset 中的每一位都默认为 \(0\)

  2. bitset<10> s(10);//bitset(unsigned long val)
    cout << s << endl;//0000001010
    

    当填入数字时,会将其转化为二进制形式,当数字最高位超出 bitset 大小时,会抛弃高位,只保留低位

  3. string str = "10110";
    bitset<10> s(str);//bitset(const string &s)
    cout << s << endl;//0000010110
    

    当传入一个 \(01\) 串时,是按照低位对齐将其转化的,同样当 \(str.size()\) 过大时,也是抛弃高位保留低位的

运算符

以下以 bitset<10> s(10)bitset<10> t(7) 举例

  1. operator []//访问指定位
    cout << s[1] << endl;//1
    

  1. operator ==/!=  //判断两个 bitset 是否相同
    cout << (s == t) << endl;//0
    

  1. operator ^/^= //bitset之间执行异或运算
    cout << (s ^ t) << endl;//0000001101
    

  1. operator |/|= //bitset之间执行或运算
    cout << (s | t) << endl;//0000001111
    

  1. operator &/&= //bitset之间执行与运算
    cout << (s & t) << endl;//0000000010
    

  1. operator ~//将bitset中每一位全部01反转
    cout << ~s << endl;//1111110101
    

常用的成员函数

以下以 bitset<10> s(10) 举例

  1. count() 返回 \(1\) 的数量

    cout << s.count() << endl;//2
    
  2. all() 若全部为都为 \(1\) 返回 true

    cout << s.all() << endl;//0
    
  3. a. set() 将整个 bitset 设置为 \(1\)

    s.set();
    cout << s << endl;//1111111111
    

    b. set(pos , val = true) 将某一位设置为指定值

    s.set(9, 1);
    cout << s << endl;//1000001010
    
  4. a. reset() 将整个 bitset 设置为 \(0\)

    s.reset();
    cout << s << endl;//0000000000
    

    b. reset(pos) 将某一位设置为 \(0\)

    s.reset(1);
    cout << s << endl;//0000001000
    
  5. a. flip() 将整个 bitset 全部 \(01\) 翻转,与取反类似

    s.flip();
    cout << s << endl;//1111110101
    

    b. flip(pos) 将某一位翻转

    s.flip(1);
    cout << s << endl;//0000001000
    
  6. to_string() 将其转化为 string

cout << s.to_string() << endl;//0000001010
  1. _Find_first() 返回 bitset 第一个 \(1\) 的下标,若没有的话返回其大小
cout << s._Find_first() << endl;//1
  1. _Find_next(pos) 返回第一个严格大于 pos\(1\) 位置的下标,若没有的话返回其大小
cout << s._Find_next(1) << endl;//3

bitset的应用

  1. C-条件_牛客挑战赛47

    题意

    一个 \(n\) 个点的有向图,其中有 \(m1\) 条边一定存在, 有 \(m_2\) 条边一定不存在,询问两点之间是否一定(可能)到达

    做法

    明显是个裸的 Floyd ,但是 \(n=10^3\) 显然写不了 \(O(n^3)\) 的时间复杂度的算法,因此可以考虑用 bitset 优化,将时间复杂度降至 \(O(\frac{n^3}{w})\) ,其中 \(w\) 为计算机位数,一般取 \(64\)

    代码

    void solve()
    {
        bitset<N> e1[N], e2[N]; // 1必到 2可能
        int n, m1, m2, q;
        cin >> n >> m1 >> m2 >> q;
        for (int i = 1; i <= n; i++)
            e1[i].reset(), e2[i].set(), e1[i][i] = 1;//自已一定能到自己!
        for (int i = 1; i <= m1; i++)
        {
            int u, v;
            cin >> u >> v;
            e1[u][v] = 1;
        }
        for (int i = 1; i <= m2; i++)
        {
            int u, v;
            cin >> u >> v;
            e2[u][v] = 0;
        }
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
            {
                if (e1[j][i])
                    e1[j] |= e1[i];
                if (e2[j][i])
                    e2[j] |= e2[i];
            }
        while (q--)
        {
            int x, y;
            cin >> x >> y;
            cout << (e1[x][y] ? "Yes" : "No") << " ";
            cout << (e2[x][y] ? "Yes" : "No") << "\n";
        }
    }
    
  2. Music Problem

    题意

    给定 \(n\) 个数,询问是否存在方案使得选出一些数字为 \(3600\) 的倍数

    做法

    考虑常规做法,当 \(n\geq 3600\) 时由容斥可得必定存在,当 \(n<3600\) 时直接做01背包即可

    考虑 bitset 做法,可以开一个大小为 \(7200\)bitset 状压,对于输入进来的数先取模,设取模后为 \(x\) ,可得若 \(f[i]=1\) 那么 \(f[i+x]=1\) ,该转移可以通过 bitset 或上自身左移 \(x\)

    又因为 \(i+x\) 可能大于模数,所以还需要或上 bitset 右移 \(3600-x\)

    代码

    void solve()
    {
        bitset<N> s;
        int n;
        cin >> n;
        for (int i = 1; i <= n; i++)
        {
            int x;
            cin >> x;
            x %= 3600;
            s |= (s << x) | (s >> (3600 - x));
            s[x] = 1;
        }
        cout << (s[0] ? "YES" : "NO") << "\n";
    }
    
posted @ 2023-01-12 15:15  Jadebo1  阅读(92)  评论(0编辑  收藏  举报