bitset

bitset数据类型,在\<bitset>头文件中,是一种类似于数组和字符串的数据结构。

bitset的每一个单位所占内存大小为1个位,是int类型的\frac{1}{32},同时还支持一些位运算,比bool还好用。

可以把bitset当成一个长度可自定义的二进制数,这样位运算就能想通了。

构造函数

bitset是一个类似数组的变量,所以定义是必须是bitset\<size>的形式,即要声明数组大小,支持下标访问!(下标同数组,从0到size-1)

定义一个bitset类型变量的方法有以下几种

//不可以不声明size
bitset a;   //报错

//无参,默认值0
bitset<size> a;

//整型数b为参数,那么a的值就是b的二进制表示,靠右对齐,左边补0
bitset<size> a(int b);

//字符串string类型b为参数,b中只能有'0'和'1',否则抛出异常,靠右对齐,左边补0
bitset<size> a(string b);

//字符串数组为参数,同string
bitset<size> a(char[] b);

//类似于字符串是因为可以把bitset当成字符串直接输出      注意bitset的输出是按a[n-1]-a[0]顺序输出的,与string和字符数组相反
cout << a << endl;

操作符

支持 ~、&、|、^、<<、>>、&=、|=、^=、<<=、>>=还有==、!=等操作符。位运算就是把bitset当成二进制数进行按位运算。

各操作符的时间复杂度暂定。。。

就不举例子了。

函数

bitset支持一些有用的函数

    bitset<size> a;

    //count()函数用来求bitset中1的位数
    cout << a.count() << endl;

    //size()函数求bitset的大小
    cout << a.size() << endl;

    //test(i)函数对下标i进行检查,下标是否合法(越界抛出异常),以及该下标出的值为0还是1
    cout << a.test(0) << endl;

    //any()函数检查是否有1
    cout << a.any() << endl;

    //none()函数检查是否没有1
    cout << a.none() << endl;

    //all()函数检查是否全为1
    cout << a.all() << endl;

类型转化

bitset只支持三种类型转化: string, unsigned long, unsigned long long. 注意bitset存的是二进制数,转化为整数时会自动进行转化。

bitset<size> a;

string s = a.to_string();

unsigned long b = a.to_ulong();

unsigned long long c = a.to_ullong();
NC17193 简单瞎搞题

一共有 n个数,第 i 个数是 xi, xi 可以取 [li , ri] 中任意的一个值。设 S = \sum{{x_i}^2}, 求 S 种类数。
分组背包问题。即每组物品里只能选出一个放入背包,且必须选一个,求最终背包的可能取值。
用一般的背包思路解题的话:
f[i][j]\ \ |= f[i-1][j-x[i]]
但是这样的话时间复杂度太大了,O(n*max(S)*n)
考虑状态压缩,用bitset来存储每一层每个数的01情况。
f[i]\ \ |=\ f[i-1]\ << x[i]^{2}
借助于bitset方便的位运算来大大减小时间复杂度!


#include <bitset>
#include <iostream>
using namespace std;
int n;
int l[105], r[105];
bitset<1000005> f[105];
int main(){
    std::ios::sync_with_stdio(false);
    cin >> n;
    for (int i=1;i<=n;i++)    cin >> l[i] >> r[i];
    f[0][0] = 1;
    for (int i=1;i<=n;i++){
        for (int j=l[i];j<=r[i];j++){
            f[i] |= f[i-1]<<(j*j);
        }
    }
    cout << f[n].count();
    return 0;
}

0 条评论

发表评论

邮箱地址不会被公开。