bitset常用用法&&簡單題分析


Preface

bitset,還是一個比較好用的STL,可以給一些題目做到神奇的常數優化(\(O(\frac{原來的復雜度}{機器的位數(32位or64位)})\)

關於一些具體的函數等內容可以參考,這里不再贅述。通過一些簡單的題目看一下實際運用。

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\)兩個數。

這個十分清晰,我們用bitset記錄每一個數所屬的集合,判斷是否同一集合直接and一下看看有沒有交即可。

CODE

#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

題目大意:一個人要打開或者用炸彈砸開所有的門,每個門里面有一些鑰匙,一個鑰匙對應一個門,有了一個門的鑰匙就能打開相應的門,告訴每個門里面有哪些門的鑰匙,問需要用的炸彈為多少。

我們考慮對於每一扇們單獨計算期望,根據期望的線性性質最后累加起來就是答案。

考慮一扇門怎樣才能被打開,當然是用炸彈炸開或者用鎖打開,而用炸彈炸開的話會使用一次炸彈,因此\(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;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM