引
bitset 在#include< bitset >中,用于存储 0/1 的容器
bitset的库函数
可支持左移右移等操作
set():每一位赋为 1
reset():每一位赋为 0
count():统计1的个数
size():大小
还有其它的,常用的就以上
用处
在某些情况下通过 bitset 可以优化程序的运行效率
O
(
n
w
)
O(\frac{n}{w})
O(wn)
例题
T1
贪心只能过样例
这题可以用 dp 做,转移方程很简单:
f
i
,
j
=
∨
k
=
a
b
f
i
−
1
,
j
−
k
2
f_{i,j}=\vee_{k=a}^b f_{i-1,j-k^2}
fi,j=∨k=abfi−1,j−k2
然后或运算可以用bitset优化
#include <iostream>
#include <cstdio>
#include <bitset>
using namespace std;
const int N = 101;
int n, a[N], b[N];
bitset<N *N *N> f[N];
int main() {
cin >> n;
for (int i = 1; i <= n; ++i)
cin >> a[i] >> b[i];
f[0][0] = 1;
for (int i = 1; i <= n; ++i)
for (int j = a[i]; j <= b[i]; ++j)
f[i] |= (f[i - 1] << (j * j));
cout << f[n].count();
}
T2
Two Arrays
先按
w
i
w_i
wi排序
先考虑暴力枚举一个i,对每一个i去找到合法的最小的j即可,是
O
(
n
2
m
)
O(n^2m)
O(n2m)
若对每个
a
i
a_i
ai开个bitset就好了,是
O
(
n
2
m
w
)
O(\frac{n^2m}w)
O(wn2m)
注意优化空间
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
const int N=1e5+10;
const int M=5e5+10;
int n,m,lim,v[M],len,cnt[M],ans=2e9+10,idx[M],tot;
vector<int>buc[M];
struct st{
int a[6],v;
bool operator <(const st &T)const{
return v<T.v;
}
}t[N];
bitset<N>s[800];
int main(){
cin>>n>>m;lim=sqrt(n*m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)
scanf("%d",&t[i].a[j]),v[++len]=t[i].a[j];
scanf("%d",&t[i].v);
}
sort(t+1,t+1+n);
sort(v+1,v+1+len);
len=unique(v+1,v+1+len)-v-1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
buc[t[i].a[j]=lower_bound(v+1,v+1+len,t[i].a[j])-v].pb(i),cnt[t[i].a[j]]++;
for(int i=1;i<=len;i++)
if(cnt[i]>=lim){
idx[i]=++tot;
for(int x:buc[i])s[tot].set(x);
}
bitset<N>tmp;
for(int i=1;i<=n;i++){
tmp.reset();
for(int j=1;j<=m;j++)
if(idx[t[i].a[j]]) tmp|=s[idx[t[i].a[j]]];
tmp.flip();
for(int j=1;j<=m;j++)
if(!idx[t[i].a[j]])
for(int x:buc[t[i].a[j]])tmp.reset(x);
int pos=tmp._Find_next(0);
if(pos<=n) ans=min(ans,t[i].v+t[pos].v);
}
printf("%d\n",ans==2e9+10?-1:ans);
}
T3 退役的你
CQYZ出的题,比较良心,可惜没做
给定大小为 n n n 的整数集合 S S S ,求一个大小为 K K K 的整数集合 T T T, 使 0 < T i < 2 30 0<T_i<2^{30} 0<Ti<230,最大化
∑ x ∈ S ∑ y ∈ T [ x & y = y ] \sum_{x\in S}\sum_{y\in T} [x\& y=y] ∑x∈S∑y∈T[x&y=y]
贪心地在优先队列中先放
2
30
−
1
2^{30}-1
230−1,每次选择其中一个数
x
x
x加入
T
T
T,
,然后考虑将
x
x
x某一位上的一变为零得到
x
′
x'
x′ ,计算
x
′
x'
x′ 的贡献,并把 加入
x
′
x'
x′待选集合,就行了,然后计算
x
′
x'
x′ 的贡献可以bitset优化
#include<bits/stdc++.h>
using namespace std;
const int N = 5e5+7, M = 1e3+7, P = 1e9+7;
int n, K, S[N], ans[M];
priority_queue<pair<int, int> > pq;
bitset<N> bit[30],bt[M];
unordered_map<int, int> vis;
int main(){
freopen("afo.in", "r", stdin);
freopen("afo.out", "w", stdout);
scanf("%d%d",&n,&K);
for(int i = 1; i <= n; i++) {
scanf("%d", &S[i]);
for(int j = 0; j < 30; j++)
if(S[i] & (1 << j)) bit[j][i] = 1;
}
pq.push(make_pair(n, (1 << 30) - 1));
for(int T = 1; T <= K; T++) {
int x = pq.top().second;
ans[T] = x;
pq.pop();
printf("%d ", x);
if(T > 1)
bt[T] = bt[vis[x]] | bit[__builtin_ctz(x ^ ans[vis[x]])];
for(int i = 0; i < 30; i++) if((x & (1 << i)) && !vis.count(x ^ (1 << i))){
vis[x ^ (1 << i)] = T;
bitset<N> tmp = bt[T] | bit[i];
pq.push(make_pair(n - tmp.count(), x ^ (1 << i)));
}
}
}
T4 Substrings in a String
题目
考虑暴力
对于每个2询问,
O
(
∣
s
∣
∣
y
∣
)
O(|s||y|)
O(∣s∣∣y∣)暴力统计答案,因为
∑
∣
y
∣
<
=
1
e
5
\sum|y|<=1e5
∑∣y∣<=1e5
所以为
O
(
n
2
)
O(n^2)
O(n2)
用bitset优化匹配的过程后为
O
(
n
2
w
)
O(\frac{n^2}w)
O(wn2),吊打标算
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int q;
bitset<N> mp[26],ans;
char s[N],c[N];
int main(){
scanf("%s%d",s+1,&q);
int n=strlen(s+1);
for(int i=1;i<=n;i++)mp[s[i]-'a'][i]=1;
while(q--){
int op,x,y;
scanf("%d",&op);
if(op==1){
scanf("%d%s",&x,c);
mp[s[x]-'a'][x]=0;mp[c[0]-'a'][x]=1;
s[x]=c[0];
}
else {
scanf("%d%d%s",&x,&y,c);
int len=strlen(c);
ans.set();
for(int i=0;i<len;i++)ans&=(mp[c[i]-'a']>>i);
printf("%d\n",max(0,(int)(ans>>x).count()-(int)(ans>>(y-len+2)).count()));
}
}
}
就这样