洛谷P6599 「EZEC-2」异或【题解】

题目大意

T T T组数据,每组数据给定两个 l , n ∈ N ∗ l,n\in\mathbb{N*} l,nN,构造一个长为 l l l,每个元素不超过 n n n的数组
令他为 a a a,要使
∑ i = 1 l ∑ j = 1 i − 1 a i ⊕ a j \sum_{i=1}^l\sum_{j=1}^{i-1}a_i\oplus a_j i=1lj=1i1aiaj
最大,问最大值为多少

浅浅谈一下?

  • 首先,我们肯定从那个式子入手,我们可以发现 ∑ i = 1 l ∑ j = 1 i − 1 \sum_{i=1}^l\sum_{j=1}^{i-1} i=1lj=1i1这个东西,就是让一个数组里的每两个元素一一异或
  • 于是,问题就转变成了你需要构造一个 a a a数组,里面的每两个元素一一异或的值加起来最大
  • 我们继续转化,发现异或就是把每个数变成二进制,进行运算的,所以我们就可以想象有一堆二进制数,他们现在要一一异或
  • 我们来认识一下异或: ⊕ \oplus
  • 运算规则
  • 只要不一样就是 1 1 1,不一样就是 0 0 0
  • 例子: 0 1 ( 2 ) ⊕ 1 1 ( 2 ) = 1 0 ( 2 ) 01_{(2)} \oplus 11_{(2)}=10_{(2)} 01(2)11(2)=10(2)
  • 发现了什么?
  • 只有两边各有一个 0 0 0 1 1 1这一位才为 1 1 1
  • 我们再来认识一下位值
  • 假设有一个 10 1 ( 2 ) 101_{(2)} 101(2),它的十进制是什么?
  • 是不是 4 + 1 = 5 4+1=5 4+1=5?所以第三位 1 1 1它的值就是 2 3 − 1 = 4 2^{3-1}=4 231=4
  • 我们归纳一下,如果一个二进制数,它的第 k k k位是1,那么那一位贡献的值就是 2 k − 1 2^{k-1} 2k1
  • 好啦,以上就是前置芝士

回到本题

  • 既然我们吧那个式子转换成一堆二进制一一异或,我们就可以每一位每一位的看
  • 假如现在有 l l l个二进制数,我们单独看看第 k k k
  • 假设第 k k k位有 x x x 0 0 0.那么第 k k k位就有 l − x l-x lx 1 1 1
  • 现在我们要看看这一堆 0 0 0 1 1 1对原式有什么贡献
  • 根据前置芝士,只有一个 0 0 0和一个 1 1 1才能有一个 1 1 1
  • 所以第 1 1 1 0 0 0可以和其他 l − x l-x lx 1 1 1一一异或成为 l − x l-x lx 1 1 1
  • 同理,第 2 2 2个,第 3 3 3个……都可以产生 l − x l-x lx 1 1 1
  • 所以共可以产生 x ⋅ ( l − x ) x\cdot (l-x) x(lx) 1 1 1,而第 k k k 1 1 1贡献的值为 2 k − 1 2^{k-1} 2k1,所以总共贡献的值为
  • 2 k − 1 ⋅ x ⋅ ( l − x ) 2^{k-1}\cdot x \cdot (l-x) 2k1x(lx)
  • 所以,如果我们设 p p p n n n的二进制位数的话
    ∑ i = 1 l ∑ j = 1 i − 1 a i ⊕ a j = ∑ i = 1 p 2 i − 1 ⋅ x ⋅ ( l − x ) \sum_{i=1}^l\sum_{j=1}^{i-1}a_i\oplus a_j=\sum_{i=1}^p2^{i-1}\cdot x \cdot (l-x) i=1lj=1i1aiaj=i=1p2i1x(lx)
  • 要使那个式子最大,首先要使 2 i − 1 ⋅ x ⋅ ( l − x ) 2^{i-1}\cdot x \cdot (l-x) 2i1x(lx)这个最大
  • 我们发现 2 i − 1 2^{i-1} 2i1是常数,不看他,也就是要 x ⋅ ( l − x ) x\cdot (l-x) x(lx)最大
  • 假如你学过二次函数
    x ⋅ ( l − x ) = − x 2 + l x x\cdot (l-x)=-x^2+lx x(lx)=x2+lx
  • 该二次函数开口向下,有最大值
  • 也就是当 x = − b 2 a = − l − 2 = l 2 x=-\frac{b}{2a}=\frac{-l}{-2}=\frac{l}{2} x=2ab=2l=2l时取最大值
  • 这里要纠正一下,因为只有可能是整数,所以我们这里向下取整一下(和向上取整没区别)
  • 原式就等于 ⌊ l 2 ⌋ ⋅ ( l − ⌊ l 2 ⌋ ) \left \lfloor \frac{l}{2}\right \rfloor\cdot (l-\left \lfloor \frac{l}{2}\right \rfloor) 2l(l2l)
  • 于是我们就可以得到一个式子(注意, ∑ \sum 具有结合律)
    ∑ i = 1 p 2 i − 1 ⋅ ⌊ l 2 ⌋ ⋅ ( l − ⌊ l 2 ⌋ ) = ⌊ l 2 ⌋ ⋅ ( l − ⌊ l 2 ⌋ ) ⋅ ∑ i = 1 p 2 i − 1 \begin{aligned} &\sum_{i=1}^p2^{i-1}\cdot\left \lfloor \frac{l}{2}\right \rfloor\cdot (l-\left \lfloor \frac{l}{2}\right \rfloor)\\ =&\left \lfloor \frac{l}{2}\right \rfloor\cdot (l-\left \lfloor \frac{l}{2}\right \rfloor)\cdot\sum_{i=1}^p2^{i-1} \end{aligned} =i=1p2i12l(l2l)2l(l2l)i=1p2i1
  • 对于 ∑ i = 1 p 2 i − 1 \sum_{i=1}^p2^{i-1} i=1p2i1我们可以用等比数列的求和公式,它就变成了 2 p − 1 2^p-1 2p1
  • 所以我们要求的就是
    ⌊ l 2 ⌋ ⋅ ( l − ⌊ l 2 ⌋ ) ⋅ 2 p − 1 \left \lfloor \frac{l}{2}\right \rfloor\cdot (l-\left \lfloor \frac{l}{2}\right \rfloor)\cdot2^{p}-1 2l(l2l)2p1
  • 最后一个问题: p p p是什么?
  • 我们立刻就会想到与 log ⁡ n \log n logn有关系,我们来手摸一下
  • 如果是 8 = 100 0 ( 2 ) 8=1000_{(2)} 8=1000(2) log ⁡ 8 = 3 \log 8=3 log8=3,位数是 4 4 4,所以我们要加一
  • 再来一个 7 = 11 1 2 7=111_{2} 7=1112, log ⁡ 7 = 2.... \log 7 = 2.... log7=2....,位数是 3 3 3,所以我们要向下取整在加一
  • 归纳一下
    p = ⌊ log ⁡ n ⌋ + 1 p= \left \lfloor \log n\right \rfloor + 1 p=logn+1
  • 于是代码就出来了

C o d e \mathcal{Code} Code

#include<bits/stdc++.h>

using namespace std;
#define int unsigned long long
const int MAXN = 5e5 + 7, mod = 1e9 + 7;

int T, n, l;

signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);
	
	cin >> T;
	while (T--) {
		cin >> n >> l;
		if (n == 1) cout << 0 << endl;
		else cout << ((l / 2 * (l - l / 2)) % mod * ((int)pow(2, (int)log2(n) + 1) - 1)) % mod << endl;
	}
	return kkksc03;
}

完结撒花✿✿ヽ(°▽°)ノ✿

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值