【位运算知识+前缀思路+后缀思路】CS Course HDU - 6186

本文介绍了一种使用位运算解决区间查询问题的方法。具体包括两种思路:一是记录序列中每个数在每位上的累加值,利用位运算特性进行快速求解;二是记录前缀和后缀的位运算结果。附带提供了两种思路的实现代码。

Think:
1知识点:位运算
2题意:输入一个序列,询问当暂时取出一个数之后,输出剩下的所有数的从左区间至右区间的与/或/异或的值
3思路:
1>记录序列内所有数的在每一位上的累加值,进而通过与运算(同为1才为1)/或运算(存在1即为1)/异或运算(“撤销功能”:异或一个数2遍等于不异或这个数)的性质进行求解
2>记录前缀+记录后缀
4思考与反思:
1>注意如何将一个十进制数转化为其对应的二进制数
2>异或符号不要写错

vjudge题目链接

以下为Accepted代码——思路1

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

int a[101400], num[40], tmp[40];

void Sep(int x);
void Ans(int n, int id, int vor);

int main(){
    int n, m, i, id, vor;
    while(~scanf("%d %d", &n, &m)){
        memset(num, 0, sizeof(num));
        scanf("%d", &a[1]);
        vor = a[1];
        Sep(a[1]);
        for(i = 2; i <= n; i++){
            scanf("%d", &a[i]);
            vor ^= a[i];
            Sep(a[i]);
        }
        while(m--){
            scanf("%d", &id);
            Ans(n, id, vor);
        }
    }
    return 0;
}
void Sep(int x){
    for(int i = 0; i < 32; i++){
        num[i] += x%2;
        x /= 2;
        if(!x)
            break;
    }
}
void Ans(int n, int id, int vor){
    int x = a[id], y, z;
    memset(tmp, 0, sizeof(tmp));
    for(int i = 0; i < 32; i++){
        tmp[i] += x%2;
        x /= 2;
        if(!x)
            break;
    }
    y = z = 0;
    for(int i = 0; i < 32; i++){
        if(num[i]-tmp[i] == n-1)
            y += (1<<i);
        if(num[i]-tmp[i] > 0)
            z += (1<<i);
    }
    printf("%d %d %d\n", y, z, vor^a[id]);
}

以下为Accepted代码——思路2

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 101400;

int a[N];
int u1[N], v1[N], w1[N];
int u2[N], v2[N], w2[N];

int main(){
    int n, m, i, id;
    while(~scanf("%d %d", &n, &m)){
        for(i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        u1[1] = v1[1] = w1[1] = a[1];
        for(i = 2; i <= n; i++){
            u1[i] = u1[i-1] & a[i];
            v1[i] = v1[i-1] | a[i];
            w1[i] = w1[i-1] ^ a[i];
        }
        u2[n] = v2[n] = w2[n] = a[n];
        for(i = n-1; i >= 1; i--){
            u2[i] = u2[i+1] & a[i];
            v2[i] = v2[i+1] | a[i];
            w2[i] = w2[i+1] ^ a[i];
        }
        while(m--){
            scanf("%d", &id);
            if(id == 1)
                printf("%d %d %d\n", u2[2], v2[2], w2[2]);
            else if(id == n)
                printf("%d %d %d\n", u1[n-1], v1[n-1], w1[n-1]);
            else
                printf("%d %d %d\n", u1[id-1] & u2[id+1], v1[id-1] | v2[id+1], w1[id-1] ^ w2[id+1]);
        }
    }
    return 0;
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值