zoukankan      html  css  js  c++  java
  • HDU 6085 Rikka with Candies

    之前不知道bitset这种结构,估计知道了,也想不起来用,看博客说STL里面没有区间操作,用的话会超时,要自己手写,这里我找了网上大牛手写的bitset好好解析了一番,解题思路的话就是由于只需要求出种数的奇偶性,容易发现奇偶性的变化和2进制中亦或的结果相同。于是想到利用位操作来进行优化。对于Bi ,可以不断的枚举区间 [kBi,(k+1)Bi1] ,而这一段区间中值 kBi+d 对Bi 取模的结果为 d ,即该区间对Bi 取模结果为区间 [0,Bi1] 。于是根据 Ai 的值将取放置到区间中的对应位置,再不断枚举区间 [kBi,(k+1)Bi1] 和区间 [0,B1]做亦或操作。询问时只要查询对应位的01值即可。实现时发现bitset没有区间操作的功能,所有利用unsigned long long 手动实现了bitset。最后复杂度为 O(n264) 。

    以上摘自大牛题解:

    自己注释过的代码,帮助理解:

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define ULL unsigned long long
    const int maxn=5e4+50;
    struct Bitset
    {
        ULL bit[1600];
        void reset()
        {
            memset(bit,0,sizeof bit);
        }
        void flip(int pos)//把第pos位置一
        {
            bit[pos>>6]^=1llu<<(pos&63);
        }
        bool judge(int pos)//判断第pos位是否是1
        {
            return bit[pos>>6]&(1llu<<(pos&63));
        }
    }A,ans;
    
    int b[maxn];
    ULL pre[66];
    int main()
    {
        freopen("input.txt","r",stdin);
        int T,n,m,q,a,mx;
        scanf("%d",&T);
        pre[0]=1;
        for(int i=1;i<64;i++)
            pre[i]=pre[i-1]|(1ll<<i);
        while(T--)
        {
            scanf("%d%d%d",&n,&m,&q);
            A.reset();
            ans.reset();
            mx=0;//最大的ax,是数据处理的范围
            for(int i=0;i<n;i++)
            {
                scanf("%d",&a);
                A.flip(a);
                mx=max(a,mx);
            }
            for(int i=0;i<m;i++)
            {
               scanf("%d",&b[i]);
               for(int j=0;j*b[i]<=mx;j++)
               {
                   int len=j*b[i];
                   int idx1=len>>6,p1=len&63;
                   len+=b[i]-1;
                   int idx2=len>>6,p2=len&63;
                   if(idx1==idx2)//在同一组64位bit里面
                   {
                       ULL tmp=A.bit[idx1]>>p1;
                       tmp&=pre[p2-p1];//高位清零
                       ans.bit[0]^=tmp;//得出其中一组b区间的贡献
                   }
                   else//b的异或区间跨越多个64位组
                   {
                       int curid=0,curpos=0;//ans的异或起始区间
                       ULL tmp=A.bit[idx1]>>p1;
                       tmp&=pre[63-p1];//从P1到本组最高位都要操作
                       ans.bit[0]^=tmp;
                       curpos=63-p1;//已经操作至第curpos位
                       for(int k=idx1+1;k<idx2;k++)
                       {
                           if(curpos==63)//说明p1是从第0位操作的,那么接下来的所有整组可以直接操作
                           {
                              ans.bit[++curid]^=A.bit[k];
                           }
                           else//p1不是从第0位操作的,那么就是半组操作
                            {
                                tmp=A.bit[k]<<(curpos+1);//补答案bit中的高位
                                ans.bit[curid++]^=tmp;
                                tmp=A.bit[k]>>p1;//继续操作补完高位后剩下的低位
                                tmp&=pre[curpos];
                                ans.bit[curid]^=tmp;//答案bit中新的一组又操作了pos位
                            }
                       }
                       if(curpos==63)//相当于p1等于0了
                       {
                           curid++;
                           tmp=A.bit[idx2]&pre[p2];
                           ans.bit[curid]^=tmp;
                       }
                       else
                       {
                           if(p2<p1)//直接补上最后p2个,因为
                           {
                               tmp=A.bit[idx2]&pre[p2];
                               tmp<<=curpos+1;//左移之后,把最后的p2位来补高位,同上
                               ans.bit[curid]^=tmp;
                           }
                           else//p2比较大的时候,要分成两次,第一次补高位,加下来操作剩余位
                           {
                               tmp=A.bit[idx2]<<(curpos+1);
                               ans.bit[curid++]^=tmp;
                               tmp=A.bit[idx2]>>p1;
                               tmp&=pre[p2-p1];
                               ans.bit[curid]^=tmp;
                           }
                       }
                   }
               }
            }
            while(q--)
            {
                int k;
                scanf("%d",&k);
                if(ans.judge(k))
                    printf("1
    ");
                else
                    printf("0
    ");
            }
        }
        return 0;
    }
  • 相关阅读:
    nodejs中 underscore 包有什么作用
    how to download a file with Nodejs(without using third-party libraries)用node下载文件
    nodejs 操作文件系统读取写入文件
    Express URL跳转(重定向)的实现
    nodejs处理页面跳转url地址的处理
    MongoDB和MySQL的区别
    Mysql简单介绍
    MongoDB索引原理
    redis GEO地理位置命令介绍
    lfyzoj104 Counting Swaps
  • 原文地址:https://www.cnblogs.com/MeowMeowMeow/p/7389068.html
Copyright © 2011-2022 走看看