HDU6085 Rikka with Candies

题目链接

题意

​ 存在两个长度分别为 n,m 的数组 A,B 。有 q 个询问,每个询问给出一个数字 k ,可以得到使得 AimodBj=k 的种数。求该种数的奇偶性。

分析

​ 由于只需要求出种数的奇偶性,容易发现奇偶性的变化和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) 。=-=赛时比较蠢,采用移位的方式将高位置零。本机和测评机果然还是与区别,猜测是左移过程中高位补1导致一直Wa。。赛后采用&操作的方式将高位置零就过了。。。果然还是太菜了啊。实现过程可以看代码。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define ULL unsigned long long
#define MAXN 50050
struct Bitset{
    ULL bit[1600];
    void reset(){
        memset(bit,0,sizeof(bit));
    }
    void flip(int pos){
        bit[pos>>6]^=1llu<<(pos&63);
    }
    bool judge(int pos){
        return bit[pos>>6]&(1llu<<(pos&63));
    }
    void
}A,ans;
int b[MAXN];
ULL prebit[66];
int main(){
    int T,n,m,q,a,mx;
    cin>>T;
    prebit[0]=1;
    for(int i=1;i<64;++i)
        prebit[i]=prebit[i-1]|(1ll<<i);
    while(T--){
        scanf("%d %d %d",&n,&m,&q);
        A.reset();
        ans.reset();
        mx=0;
        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){
                    ULL tmp=A.bit[idx1]>>p1;
                    tmp&=prebit[p2-p1];
                    ans.bit[0]^=tmp;
                }
                else{
                    int curidx=0,curpos=0;
                    ULL tmp=A.bit[idx1]>>p1;
                    tmp&=prebit[63-p1];
                    ans.bit[0]^=tmp;
                    curpos=63-p1;
                    for(int k=idx1+1;k<idx2;++k){
                        if(curpos==63){
                            curidx++;
                            ans.bit[curidx]^=A.bit[k];
                        }
                        else{
                            tmp=A.bit[k]<<(curpos+1);
                            ans.bit[curidx++]^=tmp;
                            tmp=A.bit[k]>>p1;
                            tmp&=prebit[curpos];
                            ans.bit[curidx]^=tmp;
                        }
                    }
                    if(curpos==63){
                        curidx++;
                        tmp=A.bit[idx2]&prebit[p2];
                        ans.bit[curidx]^=tmp;
                    }
                    else{
                        if(p2<p1){
                            tmp=A.bit[idx2]&prebit[p2];
                            tmp<<=curpos+1;
                            ans.bit[curidx]^=tmp;
                        }
                        else{
                            tmp=A.bit[idx2]<<(curpos+1);
                            ans.bit[curidx++]^=tmp;
                            tmp=A.bit[idx2]>>p1;
                            tmp&=prebit[p2-p1];
                            ans.bit[curidx]^=tmp;
                        }
                    }
                }
            }
        }
        while(q--){
            int k;
            scanf("%d",&k);
            if(ans.judge(k))
                printf("1\n");
            else
                printf("0\n");
        }
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值