洛谷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;
}

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

### Python 实现 EZEC-4.5 走方格问题 以下是基于动态规划方法的 Python 实现,用于解决 P6855「EZEC-4.5」走方格问题。该实现的时间复杂度为 \( \Theta(mn) \),能够高效计算从左上角到右下角的最大权值路径。 #### 动态规划核心逻辑 通过两次遍历分别计算两个方向上的最大路径和: 1. **从前向后**:从起点 (1, 1) 到终点 (n, m) 的最大路径和。 2. **从后向前**:从终点 (n, m) 返回起点 (1, 1) 的最大路径和。 最终结果可以通过枚举每一个可能被置零的位置来获得全局最优解[^3]。 ```python def solve_ezec_4_5(a): n = len(a) m = len(a[0]) # 初始化 dp 数组 d = [[0] * (m + 1) for _ in range(n + 1)] # 前向 DP 表 p = [[0] * (m + 1) for _ in range(n + 1)] # 后向 DP 表 # 计算前向最大路径和 for i in range(1, n + 1): for j in range(1, m + 1): d[i][j] = max(d[i - 1][j], d[i][j - 1]) + a[i - 1][j - 1] # 计算后向最大路径和 for i in range(n, 0, -1): for j in range(m, 0, -1): p[i][j] = max(p[i + 1][j], p[i][j + 1]) + a[i - 1][j - 1] # 枚举每个可以置零的点,找到最小化的最大路径和 result = float('inf') for i in range(1, n + 1): for j in range(1, m + 1): current_max_path_sum = d[i][j] + p[i][j] - a[i - 1][j - 1] result = min(result, current_max_path_sum) return result # 测试数据 if __name__ == "__main__": grid = [ [1, 2, 3], [4, 5, 6], [7, 8, 9] ] answer = solve_ezec_4_5(grid) print(f"Minimum maximum path sum after setting one cell to zero: {answer}") ``` 上述代码实现了动态规划的核心思想,并结合题目需求完成了对矩阵中某一点设置为零的操作以优化路径权重[^4]。 --- ### 关键点解析 1. **状态定义** 定义 `d[i][j]` 和 `p[i][j]` 分别表示到达 `(i, j)` 的最大路径和以及从 `(i, j)` 出发的最大路径和。 2. **转移方程** 对于任意位置 `(i, j)`, - 前向传递关系为:\( d[i][j] = \max(d[i-1][j], d[i][j-1]) + a[i][j] \)。 - 后向传递关系为:\( p[i][j] = \max(p[i+1][j], p[i][j+1]) + a[i][j] \)。 3. **边界条件** 边界情况需特别处理,例如当 `i=1` 或者 `j=1` 时,仅能依赖单一方向的状态更新。 4. **枚举策略** 遍历整个网格中的每一点作为候选置零点,记录其对应的最小化最大路径和。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值