1. 程式人生 > 其它 >bitset學習筆記 & 洛谷 P3674 小清新人渣的本願(莫隊、bitset)

bitset學習筆記 & 洛谷 P3674 小清新人渣的本願(莫隊、bitset)

推薦部落格:扶蘇的bitset淺談

筆記:

  1. 定義時可以賦值 bitset<10> b(8);bitset<1005> b(string("01010101"))

    會分別儲存為0000001000、0001010101

  2. 函式 b.to_ulong() 和 b.to_ullong() 會把b裡面的數轉化為一個 unsighed long int/unsigned long long(32位/64位)(int和long int實際上都是32位)。

    注意當b中的數字大於轉化過去的最大值時,會RE(不是b定義的位數,而是b中的數字)

  3. bitset的下標是[0,n),cout輸出時順序為 n-1 n-2 n-3……3 2 1 0。

  4. 常用函式:b.reset(); b.set(); b.test(); b.any(); b.none(); b.count(); b.flip();

    分別表示:全變成0;全變成1;第i位是否為1;是否有1;是否全0;1的個數;翻轉

例題:

洛谷 P1537 彈珠

物品總數很少,所以可以多重揹包轉化為01揹包。狀態轉移方程為:

\[dp[j]|=dp[j-w[i]] \]

用bitset可以將其優化,b的第i位表示能否組成價值和為i,則轉移方程為:

\[b|=b<<w[i] \]

然而實際上跑得很慢,我也不知道為啥。。

洛谷 P3674 小清新人渣的本願

莫隊+bitset優化。

開一個bitset c,第i位表示數字i有無出現。

開一個bitset d,第i位表示數字N-d是否出現。

  • 若判斷有無 a-b=x,可以轉化成 a=b+x,即判斷 c&(c<<x) 是否有1,即 c&(c<<x).any();

  • 若判斷有無 a+b=x,可以轉化成 a-(n-b)=x-n,再轉化成 (n-b)=a+(n-x),即判斷 d&(c<<(n-x)).any();

  • 若判斷有無 a*b=x,可以暴力 \(O(\sqrt x)\) 列舉 x 的因數,\(O(1)\) 查詢即可。

然後用莫隊將詢問離線操作,保證左端點和右端點最多移動 \(n\sqrt n\) 次,而每次移動更新bitset都是 \(O(1)\)

的。

最後總的時間複雜度為 \(O(n\sqrt n + m(\frac{c}{w} + \sqrt c))\)

AC程式碼

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<bitset>
using namespace std;
template<class T>inline void read(T &x)
{
    x=0;register char c=getchar();register bool f=0;
    while(!isdigit(c))f^=c=='-',c=getchar();
    while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar();
    if(f)x=-x;
}
const int maxn=1e5+5;
int n,m,a[maxn],in[maxn],vis[maxn],sq;
bitset<maxn+5> c,d;
struct node{
	int op,l,r,x,id,ans;
}q[maxn];
bool cmp1(node a,node b){
	if(in[a.l]!=in[b.l]) return in[a.l]<in[b.l];
	if(in[a.l]&1) return a.r<b.r;
	return a.r>b.r;
}
bool cmp2(node a,node b){
	return a.id<b.id;
}
void insert(int x){
	x=a[x];
	if(vis[x]==0) c.set(x),d.set(maxn-x);
	vis[x]++;
}
void del(int x){
	x=a[x];
	if(vis[x]==1) c.reset(x),d.reset(maxn-x);
	vis[x]--;
}
int main(){
	ios::sync_with_stdio(false);
	read(n);read(m);
	sq=sqrt(n);
	if(sq*sq<n) sq++;
	int cnt=1,cnt_now=0;
	for(int i=1;i<=n;i++){
		cnt_now++;
		if(cnt_now==sq){
			cnt++;
			cnt_now=0;
		}
		in[i]=cnt;
	}
	for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1;i<=m;i++){
		read(q[i].op);read(q[i].l);read(q[i].r);read(q[i].x);q[i].id=i;
	}
	sort(q+1,q+m+1,cmp1);
	int l=1,r=0;
	for(int i=1;i<=m;i++){
		while(r<q[i].r) insert(++r);
		while(r>q[i].r) del(r--);
		while(l>q[i].l) insert(--l);
		while(l<q[i].l) del(l++);
		if(q[i].op==1) q[i].ans=(c&(c<<q[i].x)).any();
		else if(q[i].op==2) q[i].ans=(d&(c<<(maxn-q[i].x))).any();
		else {
			int sq=sqrt(q[i].x);
			for(int j=1;j<=sq;j++){
				if(q[i].x%j==0){
					if(c.test(j)&&c.test(q[i].x/j)){
						q[i].ans=1;
						break;
					}
				}
			}
		}
	}
	sort(q+1,q+m+1,cmp2);
	for(int i=1;i<=m;i++){
		if(q[i].ans) puts("hana");
		else puts("bi");
	}
	return 0;
}