bitset经常使用用法&&简单题分析

Preface

bitset,仍是一个比较好用的STL,能够给一些题目作到神奇的常数优化(\(O(\frac{原来的复杂度}{机器的位数(32位or64位)})\)html

关于一些具体的函数等内容能够参考,这里再也不赘述。经过一些简单的题目看一下实际运用。git

Newcoder 132C 简单瞎搞题

这个东西咱们感受能够用相似背包的方法搞一下,记录一下哪些数是是当前能够取到的,能够滚存一下。数组

可是咱们考虑到这样bool数组赋值可能会使复杂度达到\(O(n^4)\),所以咱们能够把bool数组改成bitset闭包

这样更新的时候咱们先左移再不停地累计答案便可。函数

CODE优化

#include<cstdio>
#include<cctype>
#include<bitset>
using namespace std;
const int N=1000005;
int n,q,l,r;
bitset <N> ans,t;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i,j; read(n); ans[0]=1;
    for (i=1;i<=n;++i)
    {
        read(l); read(r); t.reset();
        for (j=l;j<=r;++j) t|=ans<<j*j; ans=t;
    }
    return printf("%d",ans.count()),0;
}

POJ 2443

题目大意:给出\(n\)个集合,每一个集合中最多有\(10000\)个数,每一个数的范围为\([1,10000]\),给出\(q\)次询问,每次给出两个数\(u,v\)判断是否有一个集合中同时含有\(u,v\)两个数。spa

这个十分清晰,咱们用bitset记录每个数所属的集合,判断是否同一集合直接and一下看看有没有交便可。code

CODEhtm

#include<cstdio>
#include<cctype>
#include<bitset>
using namespace std;
const int N=1005,MAX_SIZE=10005;
int n,q,x,y;
bitset <N> bit[MAX_SIZE],t;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i,j; read(n);
    for (i=1;i<=n;++i)
    for (read(x),j=1;j<=x;++j)
    read(y),bit[y].set(i);
    for (read(q),i=1;i<=q;++i)
    {
        read(x),read(y); t=bit[x]&bit[y];
        if (t.any()) puts("Yes"); else puts("No");
    }
    return 0;
}

HDU 5036

题目大意:一我的要打开或者用炸弹砸开全部的门,每一个门里面有一些钥匙,一个钥匙对应一个门,有了一个门的钥匙就能打开相应的门,告诉每一个门里面有哪些门的钥匙,问须要用的炸弹为多少。blog

咱们考虑对于每一扇们单独计算指望,根据指望的线性性质最后累加起来就是答案。

考虑一扇门怎样才能被打开,固然是用炸弹炸开或者用锁打开,而用炸弹炸开的话会使用一次炸弹,所以\(E_i=\frac{1}{g_i}\)\(g_i\)表示有多少个点(包括本身)能够到达\(i\)

考虑这个问题,其实就是一个传递闭包,用bitset优化一下floyed便可跑过\(1000\)的数据。

Tarjan+拓扑排序貌似也能够跑,可是根本没有这个好写啊

CODE

#include<cstdio>
#include<cctype>
#include<bitset>
using namespace std;
const int N=1005;
bitset <N> d[N];
int t,n,x,y; double ans;
inline char tc(void)
{
    static char fl[100000],*A=fl,*B=fl;
    return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
    x=0; char ch; while (!isdigit(ch=tc()));
    while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
}
inline void floyed(void)
{
    for (register int i=1;i<=n;++i)
    for (register int j=1;j<=n;++j)
    if (d[j].test(i)) d[j]|=d[i];
}
int main()
{
    //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    register int i,j,s; read(t);
    for (s=1;s<=t;++s)
    {
        for (read(n),i=1;i<=n;++i) d[i].reset();
        for (i=1;i<=n;++i) 
        for (read(x),d[i].set(i),j=1;j<=x;++j)
        read(y),d[y].set(i); ans=0;
        for (floyed(),i=1;i<=n;++i)
        ans+=(double)1/d[i].count();
        printf("Case #%d: %.5lf\n",s,ans);
    }
    return 0;
}
相关文章
相关标签/搜索