【codeforces 757 Div2 C】1614/C Divan and bitwise operations题解

题目大意

n n n个非负整数 a 1 , 2 , . . . n a_{1,2,...n} a1,2,...n

m m m个信息 ( l , r , x ) (l,r,x) (l,r,x),每一组表示 a l ⊕ a l + 1 ⊕ . . . ⊕ a r = x a_l\oplus a_{l+1} \oplus ... \oplus a_r = x alal+1...ar=x (保证所有数都被覆盖)

求数组 a a a的所有子序列异或和。(有多种 a a a数组的组成话,任意输出一种情况下的和即可)

结果对 1 0 9 + 7 10^9 + 7 109+7取模

思路

通常这种异或和的题大概率是要按位进行计算

假设 a a a数组中第 y y y位上为 1 1 1的数有 A A A个,那么为了让它们在这一位异或和为 1 1 1,我们要从中任意选出奇数个,方案数有:

C A 1 + C A 3 + . . . + C A ( A & 1 ) ? A : A − 1 = 2 A − 1 C_{A}^{1}+C_{A}^{3}+...+C_{A}^{(A\&1) ? A:A-1} = 2^{A - 1} CA1+CA3+...+CA(A&1)?A:A1=2A1,

假设剩下这一位为 0 0 0的数有 B B B个,那它们可以任意选取,共有 2 B 2^B 2B种方案数,所以总方案数为

2 A − 1 ∗ 2 B = 2 n − 1 2^{A-1} * 2^B = 2^{n-1} 2A12B=2n1

可见,某一位提供的方案数,与这一位是 1 1 1的数的个数无关,只要这一位是 1 1 1的数至少有 1 1 1个,那么它提供的方案数就是 2 n − 1 2^{n-1} 2n1。如果它是第 k k k位,那它的贡献就是 2 k − 1 ∗ 2 n − 1 2 ^ {k-1} * 2 ^ {n-1} 2k12n1

所以,我们判断有哪一位至少出现过一次,然后加起来,乘以 2 n − 1 2^{n-1} 2n1,就是最终的答案了。

代码

#include <cstdio>
#include <iostream>
using namespace std;

const int maxN = 2e5 + 7;
const long long Mod = 1e9 + 7;

int T, n, m;

long long quickPow(long long a, long long b, long long c)
{
    long long tmp = a, ans = 1;
    while(b) {
        if(b & 1)
            ans = ans * tmp % c;
        tmp = tmp * tmp % c;  
        b >>= 1;  
    }
    return ans;
}

int main()
{
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &m);
        long long ans = 0;
        for(int i = 1; i <= m; ++i) {
            long long l, r, x;
            scanf("%lld%lld%lld", &l, &r, &x);
            ans |= x;
        }
        printf("%lld\n", ans * quickPow(2, n - 1, Mod) % Mod);
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值