1 条题解
-
0
CF1990B Array Craft 题解
题意回顾
给定三个整数 (),构造一个长度为 、仅由 和 组成的数组 ,使得:
- 最大前缀位置等于 :即 是满足 $\sum_{j=1}^i a_j = \max\limits_{k=1}^n \sum_{j=1}^k a_j$ 的最小下标 ;
- 最大后缀位置等于 :即 是满足 $\sum_{j=i}^n a_j = \max\limits_{k=1}^n \sum_{j=k}^n a_j$ 的最大下标 。
构造方法
将数组分为三段:
- 左段 :从右往左(下标递减)交替填入 ,即下标与 同奇偶的位置填 ,否则填 。
- 中段 :全部填 。
- 右段 :从左往右交替填入 ,即从 开始奇数位填 ,偶数位填 。
代码中的实现:
for (int i = y - 1; i; --i) // 左段,从右往左 cout << (i & 1 ? "-1 " : "1 "); for (int i = y; i <= x; ++i) // 中段 cout << "1 "; for (int i = 1, tmp = n - x; i <= tmp; ++i) // 右段 cout << (i & 1 ? "-1 " : "1 ");
正确性证明
1. 最大前缀位置
观察前缀和的变化:
- 左段 :交替填 ,使得前缀和在 和 之间反复震荡(具体取决于 的奇偶性),但始终保持 。到位置 时前缀和 。
- 进入中段 (全 )后,前缀和从位置 的值开始,每个位置 ,单调递增。
- 位置 处前缀和达到全局最大值。因为之后进入右段 ,交替填入 ,使得前缀和每隔一步减少 或不变,不会再超过 处的值。
此外,若存在某个 使得前缀和也等于最大值,必须保证 是最小的这样的下标。由于中段全 ,前缀和在 严格单调递增,故 之前的任何位置前缀和都严格小于 处。左段的前缀和始终小于等于 ,不可能达到 处的值(中段至少有一个 ,所以 处前缀和 前面最大值 )。因此 确实是唯一且最小的最大值位置。
2. 最大后缀位置
观察后缀和的变化:
- 右段 :交替填 ,后缀和(从右往左看)在 和 之间震荡,始终 。
- 中段 (全 ):从右往左看,后缀和在 区间内严格单调递增(因为每个位置都是 )。
- 左段 :交替填 ,后缀和经历 交替,始终 。
整个后缀和的最大值出现在 处。因为从 往左扫,后缀和先是 ,经过中段 时逐渐增大,在 处达到最大;再往左,后缀和因交替填 而下降,不会再超过 处的值。同时 是最大的使得后缀和等于最大值的下标,因为中段 内后缀和严格递减(从左往右看是递增,从右往左是递减),所以 之后的位置后缀和都严格小于 处。
复杂度
每组数据只需 时间输出。所有数据 总和 ,完全可以通过。
参考代码
#include <bits/stdc++.h> #define I return #define AK 0 #define IOI ; using namespace std; typedef long long ll; typedef pair<int, int> pii; int t, n, x, y; int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin >> t; while (t--) { cin >> n >> x >> y; for (int i = y - 1; i; --i) cout << (i & 1 ? "-1 " : "1 "); for (int i = y; i <= x; ++i) cout << "1 "; for (int i = 1, tmp = n - x; i <= tmp; ++i) cout << (i & 1 ? "-1 " : "1 "); cout << '\n'; } I AK IOI }
- 1
信息
- ID
- 6897
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者