bitset入门

Explosion HDU - 5036
题意:给出n个箱子。每个箱子上都有锁。一把钥匙只能开一把锁,一把锁只有一个钥匙。当然,对于有些没法用钥匙开的箱子,我们必须暴力打开。给出每个箱子中钥匙的数目和具体能开那个箱子,求暴力开箱子的数目的期望,使所有的箱子被打开。

心得:

  1. 期望的可加性。。http://blog.csdn.net/grooowing/article/details/45000205
    感觉忘了挺多,因为这个地方总是以为期望是不可+的。
    参考http://www.cnblogs.com/mengfanrong/p/5186386.html
 思路:每一个房间期望都是可加的。参考

单独考虑一个房间,假设有k个房间被炸开都会导致这个房间被打开。

那么炸一次这个房间被打开的概率即为kn。也就意味着为了把这个房间打开的期望炸的次数为nk。所有加起来后除以n就可以。bitset优化。


bitset<N>b[N];
int  cnt[N];
int main(){
    int T;sf("%d",&T);
    int cas=0;
    int n;
    while(T--){
        sf("%d",&n);
        rep(i,0,n-1)b[i].reset(),cnt[i]=0,b[i][i]=1;
        rep(i,0,n-1){
            int x;sf("%d",&x);
            while(x--){
                int t;sf("%d",&t);
                b[i][t-1]=1;
            }
        }
        mem(cnt,0);
        rep(i,0,n-1)
            rep(j,0,n-1)
                if(b[j][i])
                    b[j]|=b[i];
        rep(i,0,n-1)
            rep(j,0,n-1)
                if(b[i][j])cnt[j]++;
        double ans=0;
        rep(i,0,n-1)ans+=1.0/cnt[i];

        pf("Case #%d: %.5lf\n",++cas,ans);
    }
}

—————————————————————————————————————
参考http://blog.csdn.net/sin_xf/article/details/47080125
题意:给n个点m条边,问最多可以添加几条边使图为完全二分图

分析:如果二分图没有限制,看到是两边分别为n/2个点和n-n/2个点的最优但是可 能出现大于此点的情况,比如n=4,m=3,边为1 2,1 3,1 4.此时完全二分图边最多为3,所以要求得二分图左边或者右边可达到的离n/2最近的点数是多少为最优解,于是采用染色分别求出各个联通快的2种颜色的各个点数,然后用推出能达到的点数,这里dp[i]的下一个状态是dp[i+1]+d[i+1][0]和dp[i+1][1](dp[i]为前i个二分图的能达到的最大点数
),直接做n*n的复杂度,于是采用bitset优化,复杂度降为n,然后在结果中选取最优

感悟:
这个地方的bitset对于dp 的优化很大。。。

int n,m;
int e,fst[N],nxt[N<<1],vv[N<<1];
int col[N];
bitset<10010>dp;
void add(int u,int v){
    nxt[e]=fst[u];vv[e]=v;fst[u]=e++;
}

int a1,a2;
void dfs(int u,int val){
    col[u]=1;
    if(val==1)a1++;
    else a2++;
    for(int i=fst[u];~i;i=nxt[i]){
        int v=vv[i];
        if(!col[v])dfs(v,val^1);
    }
}
int a[N],b[N];
int main(){
    int T;sf("%d",&T);
    while(T--){
        mem(fst,-1);mem(col,0);e=0;
        sf("%d%d",&n,&m);
        rep(i,1,m){ int u,v;sf("%d%d",&u,&v);add(u,v);add(v,u); }
        int cnt=0;
        for(int i=1;i<=n;++i){
            if(!col[i]){
                ++cnt;a1=0,a2=0;
                dfs(i,1);
                a[cnt]=a1;b[cnt]=a2;
                //bug
            }
        }
        dp.reset(); dp[0]=1;
        for(int i=1;i<=cnt;++i){
            dp=(dp<<a[i])|(dp<<b[i]);
        }
        int ans=0;
        for(int i=1;i<n;++i){
            if(dp[i])ans=max(ans,i*(n-i)-m);
        }
        pf("%d\n",ans);
    }
}

题目大意:给定两个n阶矩阵,求矩阵相乘后模3.


解题思路:因为矩阵模掉3后只有012三种情况。所以对于矩阵A,记录每一行中12的位置,借助bitset。矩阵B中每一列12的位置。然后对于结果中每个位置,只要考虑11,12,2122的个数即可。

感悟:
这个地方的&用的很好。。。
参考http://blog.csdn.net/keshuai19940722/article/details/38391913

int n;
bitset<N>x[N][2],y[N][2];
int solve(int xx,int yy){
    int ret=0;
    for(int i=0;i<2;++i){
        for(int j=0;j<2;++j){
            bitset<N>k;k=x[xx][i]&y[yy][j];
            ret=(ret+(i+1)*(j+1)*k.count())%3;
        }
    }
    return ret;
}
int main(){
    while(~sf("%d",&n)){
        for(int i=0;i<n;++i){
            for(int j=0;j<2;++j)
            x[i][j].reset(),y[i][j].reset();
        }
        for(int i=0;i<n;++i){
            for(int j=0;j<n;++j){
                int a;sf("%d",&a);a%=3;
                if(a)x[i][a-1].set(j,1);
            }
        }
        for(int i=0;i<n;++i){
            for(int j=0;j<n;++j){
                int a;sf("%d",&a);a%=3;
                if(a)y[j][a-1].set(i,1);
            }
        }
        for(int i=0;i<n;++i){
            for(int j=0;j<n;++j){
                pf("%d%c",solve(i,j),j==n-1?'\n':' ');
            }
        }
    }
}

参考http://blog.csdn.net/stay_accept/article/details/71167905

题意:给出n个集合(n<=1000),每个集合中最多有10000个数,每个数的范围为1~10000,给出q次询问(q<=200000),每次给出两个数u,v判断是否有一个集合中同时含有u,v两个数 

分析:一开始觉得10的8次方刚刚好。。。看了题解才知道不需要这样。。

int n;
bitset<1010>bi[N];
int main(){
    while(~sf("%d",&n)){
        rep(i,1,10000)bi[i].reset();
        rep(i,1,n){
            int x;sf("%d",&x);
            while(x--){
                int u;sf("%d",&u);
                bi[u].set(i-1,1);
            }
        }
        int q;sf("%d",&q);
        while(q--){
            int u,v;sf("%d%d",&u,&v);
            bitset<1010>k;k=bi[u]&bi[v];
            if(k.count()!=0)puts("Yes");
            else puts("No");
        }
    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值