bitset學習筆記 & 洛谷 P3674 小清新人渣的本願(莫隊、bitset)
推薦部落格:扶蘇的bitset淺談
筆記:
-
定義時可以賦值 bitset<10> b(8);bitset<1005> b(string("01010101"))
會分別儲存為0000001000、0001010101
-
函式 b.to_ulong() 和 b.to_ullong() 會把b裡面的數轉化為一個 unsighed long int/unsigned long long(32位/64位)(int和long int實際上都是32位)。
注意當b中的數字大於轉化過去的最大值時,會RE(不是b定義的位數,而是b中的數字)
-
bitset的下標是[0,n),cout輸出時順序為 n-1 n-2 n-3……3 2 1 0。
-
常用函式: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;
}