题目大意
有
T
T
T组数据,每组数据给定两个
l
,
n
∈
N
∗
l,n\in\mathbb{N*}
l,n∈N∗,构造一个长为
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=1∑lj=1∑i−1ai⊕aj
最大,问最大值为多少
浅浅谈一下?
- 首先,我们肯定从那个式子入手,我们可以发现 ∑ i = 1 l ∑ j = 1 i − 1 \sum_{i=1}^l\sum_{j=1}^{i-1} ∑i=1l∑j=1i−1这个东西,就是让一个数组里的每两个元素一一异或
- 于是,问题就转变成了你需要构造一个 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 23−1=4
- 我们归纳一下,如果一个二进制数,它的第 k k k位是1,那么那一位贡献的值就是 2 k − 1 2^{k-1} 2k−1
- 好啦,以上就是前置芝士
回到本题
- 既然我们吧那个式子转换成一堆二进制一一异或,我们就可以每一位每一位的看
- 假如现在有 l l l个二进制数,我们单独看看第 k k k位
- 假设第 k k k位有 x x x个 0 0 0.那么第 k k k位就有 l − x l-x l−x个 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 l−x个 1 1 1一一异或成为 l − x l-x l−x个 1 1 1
- 同理,第 2 2 2个,第 3 3 3个……都可以产生 l − x l-x l−x个 1 1 1
- 所以共可以产生 x ⋅ ( l − x ) x\cdot (l-x) x⋅(l−x)个 1 1 1,而第 k k k个 1 1 1贡献的值为 2 k − 1 2^{k-1} 2k−1,所以总共贡献的值为
- 2 k − 1 ⋅ x ⋅ ( l − x ) 2^{k-1}\cdot x \cdot (l-x) 2k−1⋅x⋅(l−x)
- 所以,如果我们设
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=1∑lj=1∑i−1ai⊕aj=i=1∑p2i−1⋅x⋅(l−x) - 要使那个式子最大,首先要使 2 i − 1 ⋅ x ⋅ ( l − x ) 2^{i-1}\cdot x \cdot (l-x) 2i−1⋅x⋅(l−x)这个最大
- 我们发现 2 i − 1 2^{i-1} 2i−1是常数,不看他,也就是要 x ⋅ ( l − x ) x\cdot (l-x) x⋅(l−x)最大
- 假如你学过二次函数
x ⋅ ( l − x ) = − x 2 + l x x\cdot (l-x)=-x^2+lx x⋅(l−x)=−x2+lx - 该二次函数开口向下,有最大值
- 也就是当 x = − b 2 a = − l − 2 = l 2 x=-\frac{b}{2a}=\frac{-l}{-2}=\frac{l}{2} x=−2ab=−2−l=2l时取最大值
- 这里要纠正一下,因为只有可能是整数,所以我们这里向下取整一下(和向上取整没区别)
- 原式就等于 ⌊ l 2 ⌋ ⋅ ( l − ⌊ l 2 ⌋ ) \left \lfloor \frac{l}{2}\right \rfloor\cdot (l-\left \lfloor \frac{l}{2}\right \rfloor) ⌊2l⌋⋅(l−⌊2l⌋)
- 于是我们就可以得到一个式子(注意,
∑
\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=1∑p2i−1⋅⌊2l⌋⋅(l−⌊2l⌋)⌊2l⌋⋅(l−⌊2l⌋)⋅i=1∑p2i−1 - 对于 ∑ i = 1 p 2 i − 1 \sum_{i=1}^p2^{i-1} ∑i=1p2i−1我们可以用等比数列的求和公式,它就变成了 2 p − 1 2^p-1 2p−1
- 所以我们要求的就是
⌊ 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⌋⋅(l−⌊2l⌋)⋅2p−1 - 最后一个问题: 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;
}
完结撒花✿✿ヽ(°▽°)ノ✿