1 条题解
-
0
C. 琪露诺与操作
给定长度为 的序列 。
可以执行任意次(直到长度为 )以下两种操作:
反转:$[a_1, a_2, \dots, a_n] \to [a_n, a_{n-1}, \dots, a_1]$ 差分:$[a_1, a_2, \dots, a_n] \to [a_2 - a_1, a_3 - a_2, \dots, a_n - a_{n-1}]$ 求所有可能时刻(包括中间过程)序列元素和的最大值。
解题思路 关键观察 反转操作不改变序列的和,但会改变元素顺序,从而影响后续差分的结果。
差分操作使序列长度减少 ,并且新序列的每个元素是原序列相邻两项的差。
考虑一个长度为 的序列 ,其和为 。 若先反转 再做一次差分,得到的新序列 的和恰好为 。 证明: 设 ,反转得 , 差分得 。 这些差分的和等于 $(x_{m-1}-x_m)+(x_{m-2}-x_{m-1})+\cdots+(x_1-x_2) = x_1 - x_m$, 而原序列的和 ,两者一般不相等。 更正:上述推理有误,正确结论应为: 反转后再差分得到的序列,其每个元素恰好是原差分序列对应项的相反数(顺序也反转)。 具体地,原序列的差分 ()。 反转后序列 的差分为 。 而 , ,……,。 因此新序列的和 $= -d_{m-1} - d_{m-2} - \cdots - d_1 = -(d_1+d_2+\cdots+d_{m-1})$。 而原序列的和 ,差分和 。 所以新序列的和 ,不是 。 因此上述“反转+差分”并不能直接得到 。 重新分析:实际上,题目允许任意多次操作,组合反转和差分可以实现符号变化。 已知结论(可参考 Codeforces 官方题解): 对于长度为 的序列,通过若干次操作可以得到它的差分序列(长度 ),也可以得到该差分序列的相反数(通过先反转再差分)。 因此,当我们连续进行差分操作时,每次都可以选择“是否在差分前先反转”,从而使得得到的下一层序列的和等于当前层和的相反数。 也就是说,对于当前层序列 (和为 ),我们可以:
停止操作,得到和 ;
或者继续操作一次(先反转再差分),得到下一层序列 ,其和等于 。
因此,每一层的和 都可以通过一次操作变成 (但注意:变成 后序列长度减少 ,属于下一层)。 所以对于第 层(),我们能得到的最大和就是 。 对于第 层(原序列),只能得到 (因为要得到 需要做一次操作,得到的是第 层的和,而第 层已经考虑了 )。
不断差分:从原序列开始,反复做差分(不反转),得到一系列序列:
第 次差分(原序列):,长度为 ,和为 。
第 次差分:,长度为 ,和为 。
第 次差分:,长度为 ,和为 。
……
第 次差分:,长度为 ,和为 。
根据上述分析,答案就是:
ans
max ( 𝑆 0 , ∣ 𝑆 1 ∣ , ∣ 𝑆 2 ∣ , … , ∣ 𝑆 𝑛 − 1 ∣ ) ans=max(S 0 ,∣S 1 ∣,∣S 2 ∣,…,∣S n−1 ∣) 因为对于 ,我们可以通过“先反转再差分”将 变成 ,从而获得 。
算法步骤 读入测试用例数 。
对每个测试用例:
读入 和数组 。
初始化答案 。
令当前长度 。
对 到 (即循环 次):
计算当前序列的和 。
如果 (原序列):。
否则():。
若 ,将当前序列替换为它的差分序列: 对 ,然后 。
输出 。
时间复杂度 每次差分操作 ,总长度递减,总复杂度 。
,,完全可行。
标程解析
cpp #include <bits/stdc++.h> using namespace std; long long a[1010];
int main(){ int t; cin >> t; while (t--){ int n; cin >> n; for (int i = 1; i <= n; i++) cin >> a[i]; int now = n; long long ans = -1e18; for (int i = 1; i <= n; i++){ // i 表示当前是第几次差分(从1开始) long long sum = 0; for (int j = 1; j <= now; j++) sum += a[j]; // 计算当前序列和 if (i == 1) ans = max(ans, sum); // 原序列,不加绝对值 else ans = max(ans, max(sum, -sum)); // 后续层取绝对值 // 差分:原地更新,长度减1 for (int j = 1; j < now; j++) a[j] = a[j+1] - a[j]; now--; } cout << ans << endl; } return 0; } 外层循环 从 到 ,对应 到 次差分。
每次先计算当前序列和 sum。
对第一次(i==1)只取 sum,否则取 max(sum, -sum) 即绝对值。
然后进行差分操作,长度减一。
最终输出最大值。
注意:标程中内层循环变量重名(都用 i),但由于作用域覆盖,实际能正确运行(不推荐)。建议阅读时将其理解为两个不同变量。
示例验证 示例 2
第1层:,
差分得 ,长度
第2层:,, ✅
示例 3
,
差分得
, ✅
示例 4
计算各层和的绝对值,取最大值得到 ,与输出一致。
总结 本题的核心是利用“反转+差分”可以使当前层的和变号,从而每一层(除原序列外)能贡献其绝对值。只需枚举所有差分层的和并取最大值即可。标程采用 暴力模拟,简单有效。
- 1
信息
- ID
- 6605
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者