CF1614C Divan and bitwise operations
本文最后更新于19 天前,其中的信息可能已经过时,如有错误请发送邮件到big_fw@foxmail.com

CF1614C Divan and bitwise operations

题目描述

有一次,Divan 分析了一个由 n 个非负整数组成的序列 a_1, a_2, \ldots, a_n。他对该序列的每一个非空子序列,计算其所有元素的按位异或(bitwise XOR),并将所有异或值相加,得到该序列的“舒适度”(coziness)。

如果序列 c 可以通过从序列 d 中删除若干(可能为零或全部)元素得到,则称 c 是 d 的一个子序列。例如,[1,\,2,\,3,\,4]、[2,\,4] 和 [2] 都是 [1,\,2,\,3,\,4] 的子序列,但 [4,\,3] 和 [0] 不是。

Divan 对自己的分析非常自豪,但现在他丢失了序列 a,也忘记了舒适度的值!不过,Divan 还记得关于序列 a 的 m 个连续子段的按位或(bitwise OR)值。并且,原序列的每个元素都至少包含在这 m 个区间中的某一个。

Divan 请你帮忙,根据他记得的信息,计算出序列 a 的舒适度。如果可能有多个舒适度值,输出任意一个即可。

由于结果可能非常大,请输出对 10^9+7 取模后的值。

输入格式

第一行包含一个整数 t(1 \le t \le 10^3),表示测试用例的数量。

每个测试用例的第一行包含两个整数 n 和 m(1 \le n, m \le 2 \times 10^5),分别表示序列的长度和已知的连续区间数量。

接下来的 m 行,每行描述一个区间,包含三个整数 l、r、x(1 \le l \le r \le n,0 \le x \le 2^{30} – 1),表示区间 [l, r] 的按位或值为 x。

保证每个序列元素至少被包含在某一个区间内。保证一定存在满足所有条件的序列。

保证所有测试用例中 n 的总和与 m 的总和不超过 2 \times 10^5。

输出格式

对于每个测试用例,输出任意一个满足条件的序列 a 的舒适度,对 10^9+7 取模后的值。

输入输出样例 #1

输入 #1

3
2 1
1 2 2
3 2
1 3 5
2 3 5
5 4
1 2 7
3 3 7
4 4 0
4 5 2

输出 #1

4
20
112

说明/提示

在第一个样例中,满足条件的序列之一是 [0, 2]。考虑它所有的非空子序列:

  • [0]:该子序列的按位异或为 0;
  • [2]:该子序列的按位异或为 2;
  • [0, 2]:该子序列的按位异或为 2。

所有结果之和为 4,所以答案为 4。

在第二个样例中,满足条件的序列之一是 [0,\,5,\,5]。

在第三个样例中,满足条件的序列之一是 [5,\,6,\,7,\,0,\,2]。

由 ChatGPT 4.1 翻译

思路

1. 为什么“每一位单独分析”?

在处理异或(XOR)、或(OR)等位运算题目时,不同二进制位之间是没有任何进位、借位相互影响的。因此,解题的最优策略通常是拆位计算。我们将原数组中的每个数字看作完全独立的二进制位(题目数据范围到 2^{30}-1,即最多 30 位),然后只盯着其中某一个特定的位去推导。

2. 子序列在什么情况下,该位对答案有贡献?

题解中说:“若 sum(1)%2=1 时该位才对答案有贡献”。

  • 异或的本质规则:相同为 0,不同为 1。多个数一起异或时,只有当 1 的个数为奇数时,结果的这一位才是 1;如果有偶数个 1,异或结果就是 0。
  • 因此,对于某一个特定的二进制位,我们只需要从原序列中挑出奇数个 1,再搭配上任意个 0,组成的子序列在这一位上的异或结果就是 1。只有结果为 1,才会对最终的“舒适度”数值产生贡献。

3. 最难懂的一步:组合数学推导公式

题解直接给出了公式:

2^{n-x} \cdot (\sum_{k=0}^{2k+1 \le x} C_x^{2k+1}) = 2^{n-1}

它的推导逻辑如下:

假设在长度为 n 的原序列中,当前观察的这一位上,总共有 x 个 1,那么剩下的 n-x 个数在这一位上必定都是 0。

  1. 选 1 的方案数:我们需要从这 x 个 1 中选出奇数个(1个、3个、5个……)。在组合数学中,根据二项式定理,从 x 个元素中选出奇数个元素的组合数之和,永远等于总子集数的一半: \sum_{k=0}^{2k+1 \le x} C_x^{2k+1} = 2^{x-1}
  2. 选 0 的方案数:0 无论怎么异或都不会改变结果。所以这 n-x 个 0,每个都有“选入子序列”或“不选入”两种状态,方案数为 2^{n-x}。
  3. 乘法原理合并:将两者相乘: 2^{x-1} \times 2^{n-x} = 2^{n-1}

这个结论非常重要:只要这一位上至少存在一个 1(即 x > 0),不管 1 的具体数量是多少,能让子序列异或结果为 1 的子序列总数,永远都是固定的 2^{n-1} 个

4. 为什么答案是全局或和乘以 2^{n-1}?

既然每一位只要存在 1,它对答案产生贡献的次数就固定是 2^{n-1} 次。

那么问题就变成了:到底哪些位上存在 1?

  • 题目给出了 m 个区间的按位或(OR)值。因为所有区间覆盖了整个数组,把这 m 个区间的值再全部“或”起来,等价于把原数组所有的数字全部“或”起来(即全局或和 S)。
  • 全局或和 S 的某一位如果是 1,就意味着原数组在这一位上至少有一个数字是 1
  • 因此,S 本身就代表了所有有效位的值的总和。将其整体乘以出现次数 2^{n-1},就是最终的答案: \text{Coziness} = S \times 2^{n-1} \pmod{10^9+7}

代码

const int mod=1000000007;  
int qpow(int base,int exp){  
    int res=1;  
    base%=mod;  
    while(exp){  
        if(exp&1) res=(res*base)%mod;  
        base=(base*base)%mod;  
        exp/=2;  
    }  
    return res;  
}  
  
void solve() {  
    int n,m;  
    cin>>n>>m;  
        int ans=0;  
    while(m--){  
        int l,r,x;  
        cin>>l>>r>>x;  
        ans|=x;  
    }  
    cout<<(ans*qpow(2,n-1))%mod<<endl;  
}
文末附加内容
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇