1 条题解
-
1
题意
给出长度为 的数组 ,请你构造一个长度为 的数组 满足 $\forall i \in [1,~n - 2],~\max(a_i,~a_{i + 1},~a_{i + 2}) - \min(a_i,~a_{i + 1},~a_{i + 2}) = w_i$。若不能构造输出
NO
。$n \le 10^6,~0 \le w_i \le 10^{12},~0 \le a_i \le 10^{18}$
分析
考虑令 ,则 。
在确定 考虑 对 的限制时我们发现,我们可以通过将 全部乘上 以使得 全都乘上 ,容易发现这并不会影响 带来的所有限制。因此我们发现我们在研究该限制时并不关心 的符号,我们令 ,则 。
考虑对该限制分别考虑最大值在哪一项上取到。设状态 表示考虑了 ,且 的方案是否合法。则对于所有合法情况 ,有:
- 若 ,则 。
- 若 ,则 。
- 若 ,。
仔细观察,我们发现若 , 数组中全部能取到的部分都为 ,不需要考虑其他两个情况;若 数组中存在一项为 那么 为 。这两种情况均可快速判断,而情况 3 则需要将所有合法状态 转换为 。
考虑维护 数组中连续的 段,则对于一个段 ,其转移后为 。容易发现其由一个翻转操作和一个平移操作构成。因此每次从 转移到 时,只需判断情况 1 和 2,然后再全局修改连续段的翻转和平移情况即可。若在转移到 前连续段集合为空,则无解,否则有解。
考虑如何构造 数组。我们可以在最终的连续段集合中任取一个点的值作为 ,考虑从后往前构造出整个 数组,发现只有三种情况:
- 若 可以等于 ,则令 。因为若 ,则 可以取任意可以取到的值,所以这么做并不会影响正确性。
- 若 ,则令 为任意可以取到的小于 的值。
- 若不满足上面的两个条件,则令 。
需要注意的是这里需要用到“任意可以取到的小于 的值”,这需要实现中在转移 时提前记录该项和 能否取到 值。
构造完 数组后,考虑如何构造 。这则相对简单,判断 是否等于 。若不等于,则 与 需异号,否则需同号。
最后根据 数组随意构造出满足每个元素均为非负整数的 数组即可。
代码
Code
/** * @file 1500F.cpp * @author Macesuted (i@macesuted.moe) * @date 2022-03-03 * * @copyright Copyright (c) 2022 * @brief * My Tutorial: https://macesuted.moe/article/cf1500f * */ #include <bits/stdc++.h> using namespace std; namespace io { #define SIZE (1 << 20) char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr; inline void flush(void) { return fwrite(obuf, 1, oS - obuf, stdout), oS = obuf, void(); } inline char getch(void) { return (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS++)) : *iS++); } void putch(char x) { *oS++ = x; if (oS == oT) flush(); return; } string getstr(void) { string s = ""; char c = getch(); while (c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == EOF) c = getch(); while (!(c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == EOF)) s.push_back(c), c = getch(); return s; } void putstr(string str, int begin = 0, int end = -1) { if (end == -1) end = str.size(); for (int i = begin; i < end; i++) putch(str[i]); return; } template <typename T> T read() { T x = 0; for (f = 1, c = getch(); c < '0' || c > '9'; c = getch()) if (c == '-') f = -1; for (x = 0; c <= '9' && c >= '0'; c = getch()) x = x * 10 + (c & 15); return x * f; } template <typename T> void write(const T& t) { T x = t; if (!x) putch('0'); if (x < 0) putch('-'), x = -x; while (x) qu[++qr] = x % 10 + '0', x /= 10; while (qr) putch(qu[qr--]); return; } struct Flusher_ { ~Flusher_() { flush(); } } io_flusher_; } // namespace io using io::getch; using io::getstr; using io::putch; using io::putstr; using io::read; using io::write; bool mem1; #define maxn 1000005 typedef pair<long long, long long> pll; long long a[maxn], d[maxn], w[maxn], v[maxn], limd[maxn]; set<pll> S; void solve(void) { int n = read<int>(); long long C = read<long long>(); for (int i = 1; i < n; i++) limd[i] = numeric_limits<long long>::max(); for (int i = 1; i <= n - 2; i++) w[i] = read<long long>(), limd[i] = min(limd[i], w[i]), limd[i + 1] = min(limd[i + 1], w[i]); S.emplace(0, limd[1]); long long A = +1, B = 0; for (int i = 1; i <= n - 1; i++) { if (A == +1) { while (!S.empty() && S.rbegin()->first + B > limd[i]) S.erase(--S.end()); if (!S.empty() && S.rbegin()->second + B > limd[i]) { int l = S.rbegin()->first; S.erase(--S.end()), S.emplace(l, limd[i] - B); } } else { while (!S.empty() && -S.begin()->second + B > limd[i]) S.erase(S.begin()); if (!S.empty() && -S.begin()->second + B > limd[i]) { int r = S.begin()->second; S.erase(S.begin()), S.emplace(B - limd[i], r); } } long long tw = (w[i] - B) / A; auto p = S.lower_bound({tw + 1, tw + 1}); if (p != S.begin() && (--p)->second >= tw) { v[i] = w[i]; S.clear(), S.emplace(0, limd[i + 1]), A = +1, B = 0; continue; } if (S.empty()) return putstr("NO\n"); v[i] = S.begin()->first * A + B; if (i == n - 1) break; A = -A, B = w[i] - B; tw = (w[i] - B) / A; p = S.lower_bound({tw + 1, tw + 1}); if (p == S.begin() || (--p)->second < tw) S.emplace(tw, tw); } d[n - 1] = v[n - 1]; putstr("YES\n"); for (int i = n - 2; i; i--) if (v[i] == w[i]) d[i] = w[i]; else if (d[i + 1] == w[i]) d[i] = v[i]; else d[i] = abs(w[i] - d[i + 1]); long long minVal = 0, pre = 0; for (int i = 2, id = +1; i <= n - 1; i++) { if (abs(d[i - 1]) + abs(d[i]) != w[i - 1]) id = -id; d[i] *= id; minVal = min(minVal, pre += d[i]); } a[1] = -minVal; for (int i = 2; i <= n; i++) a[i] = a[i - 1] + d[i - 1]; for (int i = 1; i <= n; i++) write(a[i]), putch(" \n"[i == n]); return; } bool mem2; int main() { #ifdef MACESUTED cerr << "Memory: " << abs(&mem1 - &mem2) / 1024. / 1024. << "MB" << endl; #endif int _ = 1; while (_--) solve(); #ifdef MACESUTED cerr << "Time: " << clock() * 1000. / CLOCKS_PER_SEC << "ms" << endl; #endif return 0; }
- 1
信息
- ID
- 253
- 时间
- 6000ms
- 内存
- 512MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者