【模板】bitset

Bitset常用操作:

bitset<size> s; //定义一个大小为size的bitset
s.count(); //统计s中1的个数
s.set(); //将s的所有位变成1
s.set(p); //将s的第p位变成1
s.reset(); //将s的所有位变成0
s.reset(p); //将s的第p位变成0
s.flip(); //将s的所有位取反
s.flip(p); //将s的第p位取反
s.to_string(); //将s转换成string

两个$bitset$运算的时间复杂度大概是$O(\frac{n}{32})$,所以能卡进去的话可以不写这个东西。

例题:

1.HDU5313-Bipartite Graph

有若干个二分图,现在你要添加一些边形成一个完全二分图,求最多可以添加多少边。

考虑对于每个二分图统计两部分的节点数$a_{i},b_i$,问题变为有两个集合,对于每个i,将$a_i$或$b_i$加入集合,使得两个集合的和尽量接近。

只需要模拟退火做一个背包,令$dp[i]$表示i是否能凑出来,最后取最接近$n/2$的能凑出来的数作为答案。用$bitset$优化该dp即可。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset> 
#define maxn 10005
#define maxm 500005
#define inf 0x7fffffff
#define ll long long

using namespace std;
int N,M,hd[maxn],to[maxm],nxt[maxm],cnt;
int l[maxn],r[maxn],tot;
bool vis[maxn];
bitset<maxn> dp;

inline int read(){
    int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}

inline void addedge(int u,int v){to[++cnt]=v,nxt[cnt]=hd[u],hd[u]=cnt;}

inline void dfs(int u,bool f){
    vis[u]=1;
    if(!f) l[tot]++; else r[tot]++;
    for(int i=hd[u];i;i=nxt[i]){
        int v=to[i];
        if(!vis[v]) dfs(v,(f^1));
    }
    return;
}

int main(){
    int T=read();
    while(T--){
        N=read(),M=read();
        tot=0;cnt=0;
        memset(hd,0,sizeof(hd));
        memset(vis,0,sizeof(vis));
        memset(l,0,sizeof(l));
        memset(r,0,sizeof(r));
        for(int i=1;i<=M;i++){
            int u=read(),v=read();
            addedge(u,v),addedge(v,u); 
        }
        for(int i=1;i<=N;i++) if(!vis[i]) tot++,dfs(i,0);
        dp.reset(); dp.set(0,1);
        for(int i=1;i<=tot;i++)
            dp=(dp<<l[i])|(dp<<r[i]);
        int ans=0;
        for(int i=1;i<=N;i++)
            if(dp[i]) ans=max(ans,i*(N-i)-M);
        printf("%d\n",ans);
    }
    return 0;
}
hdu5313

2.BZOJ2208-[Jsoi2010]连通数

给你一个有向图,求图中可达顶点对的个数。

考虑Floyd求最短路的过程是枚举中转点k后用k更新每对i,j,现在不需要求最短路而只需要判断能不能到达。

所以设$dp[k]$表示k能到达的点集的二进制表示,枚举k,i后用$dp[k]$更新$dp[i]$即可。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset>
#define maxn 2005
#define maxm 500005
#define inf 0x7fffffff
#define ll long long
 
using namespace std;
int N; char str[maxn][maxn]; 
bitset<maxn> dis[maxn];
 
inline int read(){
    int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}
 
int main(){
    N=read();
    for(int i=1;i<=N;i++){
        scanf("%s",str[i]+1);
        for(int j=1;j<=N;j++)
            if(str[i][j]-'0'||i==j) 
                dis[i].set(j); 
    }
    for(int k=1;k<=N;k++)
        for(int i=1;i<=N;i++)
            if(dis[i][k])
                dis[i]|=dis[k];
    int ans=0;
    for(int i=1;i<=N;i++) ans+=dis[i].count();
    printf("%d\n",ans);
    return 0;
}
bzoj2208

3.Hihocoder1236-Scores

在线求五维偏序的对数。

考虑可以对于每一维分别计算出满足要求的人的二进制表示后把5个二进制数与起来即为答案。

但这样空间时间两爆炸,所以考虑分块bitset,令$dp[k][i]$表示第k维前i个块的人的二进制表示。

对于每个询问的每一维二分查找出它所在的块,即可求出答案。

切忌在多重循环内使用两个$bitset$相互运算。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<bitset>
#include<cmath>
#define maxn 50005
#define maxm 305
#define inf 0x7fffffff
#define ll long long

using namespace std;
bitset<maxn> dp[5][maxm],tp,ans;
int N,M,bel[maxn],db[5][maxn];
struct node{int val,ind;}h[5][maxn];

inline int read(){
    int x=0,f=1; char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) x=x*10+c-'0';
    return x*f;
}

inline bool cmp(node a,node b){return a.val<b.val;}
inline int upb(int k,int x){
    int l=1,r=N,aans=0;
    while(l<=r){
        int mid=l+r>>1;
        if(db[k][mid]<=x) l=mid+1,aans=mid;
        else r=mid-1;
    }
    return aans;
}

int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.txt","w",stdout);
    int T=read();
    while(T--){
        N=read(),M=read();
        int len=sqrt(N);
        memset(bel,0,sizeof(bel));
        memset(db,0,sizeof(db));
        for(int i=1;i<=N;i++)
            for(int j=0;j<5;j++)
                h[j][i].val=read(),h[j][i].ind=i;
        for(int i=1;i<=N;i++) bel[i]=(i-1)/len+1;
        for(int k=0;k<5;k++){
            tp.reset(); sort(h[k]+1,h[k]+1+N,cmp);
            for(int i=1;i<=N;i++) db[k][i]=h[k][i].val;
            for(int i=1;i<=N;i++){
                tp.set(h[k][i].ind);
                if(bel[i]!=bel[i+1]) dp[k][bel[i]]=tp;
            }
        }
        int Q=read(),lasans=0;
        for(int nu=1;nu<=Q;nu++){
            for(int k=0;k<5;k++){
                int x=read()^lasans,pos=upb(k,x),id=bel[pos];
                if(pos==0) {ans.reset();continue;}
                tp.reset(); if(id>=2) tp|=dp[k][id-1];
                for(int i=(id-1)*len+1;i<=pos;i++) tp.set(h[k][i].ind);
                if(k==0) ans=tp; else ans&=tp;
            }
            lasans=ans.count();
            printf("%d\n",lasans);
        }
    }
    return 0;
}
hihocoder1236

猜你喜欢

转载自www.cnblogs.com/YSFAC/p/11208062.html
今日推荐