bitset,仍是一個比較好用的STL,能夠給一些題目作到神奇的常數優化(\(O(\frac{原來的複雜度}{機器的位數(32位or64位)})\))html
關於一些具體的函數等內容能夠參考,這裏再也不贅述。經過一些簡單的題目看一下實際運用。git
這個東西咱們感受能夠用相似揹包的方法搞一下,記錄一下哪些數是是當前能夠取到的,能夠滾存一下。數組
可是咱們考慮到這樣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; }
題目大意:給出\(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; }
題目大意:一我的要打開或者用炸彈砸開全部的門,每一個門裏面有一些鑰匙,一個鑰匙對應一個門,有了一個門的鑰匙就能打開相應的門,告訴每一個門裏面有哪些門的鑰匙,問須要用的炸彈爲多少。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; }