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;
}
相關文章
相關標籤/搜索