• bitset常用用法&&简单题分析


    Preface

    bitset,还是一个比较好用的STL,可以给一些题目做到神奇的常数优化((O(frac{原来的复杂度}{机器的位数(32位or64位)}))

    关于一些具体的函数等内容可以参考,这里不再赘述。通过一些简单的题目看一下实际运用。

    Newcoder 132C 简单瞎搞题

    这个东西我们感觉可以用类似背包的方法搞一下,记录一下哪些数是是当前可以取到的,可以滚存一下。

    但是我们考虑到这样bool数组赋值可能会使复杂度达到(O(n^4)),因此我们可以把bool数组改为bitset

    这样更新的时候我们先左移再不停地累计答案即可。

    CODE

    #include<cstdio>
    #include<cctype>
    #include<bitset>
    using namespace std;
    const int N=1000005;
    int n,q,l,r;
    bitset <N> ans,t;
    inline char tc(void)
    {
        static char fl[100000],*A=fl,*B=fl;
        return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
        x=0; char ch; while (!isdigit(ch=tc()));
        while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        register int i,j; read(n); ans[0]=1;
        for (i=1;i<=n;++i)
        {
            read(l); read(r); t.reset();
            for (j=l;j<=r;++j) t|=ans<<j*j; ans=t;
        }
        return printf("%d",ans.count()),0;
    }
    

    POJ 2443

    题目大意:给出(n)个集合,每个集合中最多有(10000)个数,每个数的范围为([1,10000]),给出(q)次询问,每次给出两个数(u,v)判断是否有一个集合中同时含有(u,v)两个数。

    这个十分清晰,我们用bitset记录每一个数所属的集合,判断是否同一集合直接and一下看看有没有交即可。

    CODE

    #include<cstdio>
    #include<cctype>
    #include<bitset>
    using namespace std;
    const int N=1005,MAX_SIZE=10005;
    int n,q,x,y;
    bitset <N> bit[MAX_SIZE],t;
    inline char tc(void)
    {
    	static char fl[100000],*A=fl,*B=fl;
    	return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
    	x=0; char ch; while (!isdigit(ch=tc()));
    	while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    }
    int main()
    {
    	//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
    	register int i,j; read(n);
    	for (i=1;i<=n;++i)
    	for (read(x),j=1;j<=x;++j)
    	read(y),bit[y].set(i);
    	for (read(q),i=1;i<=q;++i)
    	{
    		read(x),read(y); t=bit[x]&bit[y];
    		if (t.any()) puts("Yes"); else puts("No");
    	}
    	return 0;
    }
    

    HDU 5036

    题目大意:一个人要打开或者用炸弹砸开所有的门,每个门里面有一些钥匙,一个钥匙对应一个门,有了一个门的钥匙就能打开相应的门,告诉每个门里面有哪些门的钥匙,问需要用的炸弹为多少。

    我们考虑对于每一扇们单独计算期望,根据期望的线性性质最后累加起来就是答案。

    考虑一扇门怎样才能被打开,当然是用炸弹炸开或者用锁打开,而用炸弹炸开的话会使用一次炸弹,因此(E_i=frac{1}{g_i})(g_i)表示有多少个点(包括自己)可以到达(i)

    考虑这个问题,其实就是一个传递闭包,用bitset优化一下floyed即可跑过(1000)的数据。

    Tarjan+拓扑排序貌似也可以跑,但是根本没有这个好写啊

    CODE

    #include<cstdio>
    #include<cctype>
    #include<bitset>
    using namespace std;
    const int N=1005;
    bitset <N> d[N];
    int t,n,x,y; double ans;
    inline char tc(void)
    {
        static char fl[100000],*A=fl,*B=fl;
        return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(int &x)
    {
        x=0; char ch; while (!isdigit(ch=tc()));
        while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    }
    inline void floyed(void)
    {
        for (register int i=1;i<=n;++i)
        for (register int j=1;j<=n;++j)
        if (d[j].test(i)) d[j]|=d[i];
    }
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        register int i,j,s; read(t);
        for (s=1;s<=t;++s)
        {
            for (read(n),i=1;i<=n;++i) d[i].reset();
            for (i=1;i<=n;++i) 
            for (read(x),d[i].set(i),j=1;j<=x;++j)
            read(y),d[y].set(i); ans=0;
            for (floyed(),i=1;i<=n;++i)
            ans+=(double)1/d[i].count();
            printf("Case #%d: %.5lf
    ",s,ans);
        }
        return 0;
    }
    
  • 相关阅读:
    一般查找 (顺序查找)
    sscanf
    uva-11044-水题
    uva-10785-模拟水题
    uva-10596-欧拉回路
    uva-10879-因数分解
    uva-10562-二叉树
    扯皮的cplex-感觉时间不对
    cplex-Java-样例代码解析
    cplexJava源码---计算结果
  • 原文地址:https://www.cnblogs.com/cjjsb/p/9751384.html
Copyright © 2020-2023  润新知