题意理解
有 N 座山围成一圈(N 是奇数),每座山 i 会下 pi 升雨。这些雨水会平均分给左右两个大坝:左边的大坝 i-1 和右边的大坝 i 各得到 pi/2 升。大坝 i 收集到的总水量就是 ai。
所以 ai 和 pi 的关系就是:
ai=2pi+pi+1
两边乘 2:
pi+pi+1=2ai(1)
核心思路
这个式子很关键!它告诉我们:只要知道 pi,就能算出 pi+1:
pi+1=2ai−pi(2)
问题就变成了:怎么求出 p1?
因为 N 是奇数,我们可以绕一圈用 p1 把自己表示出来。从 p1 开始,反复用公式 (2) 推下去:
p2 p3 p4=2a1−p1=2a2−p2=2a2−(2a1−p1)=−2a1+2a2+p1=2a3−p3=2a3−(−2a1+2a2+p1)=2a1−2a2+2a3−p1
我们注意到一个规律:奇数项是 p1 加上一堆 ±2ai,偶数项是 −p1 加上一堆 ±2ai。
因为 N 是奇数,所以 pN 也是奇数项,可以写成:
pN=p1+2(a1−a2+a3−a4+⋯−aN−1)
注意最后一个方程 (1) 当 i=N 时是:
pN+p1=2aN
把 pN 的表达式代入:
(p1+2(a1−a2+⋯−aN−1))+p1=2aN
两边除以 2,得到:
p1=aN−a1+a2−a3+⋯+aN−1
也就是:
p1=aN+i=1∑N−1(−1)i+1ai
算法流程
- 用公式算出 p1
- 从 i=1 到 N−1,用递推式 pi+1=2ai−pi 算出所有 pi
复杂度是 O(N) 时间,O(N) 空间(存 ai 和 pi 数组)。
代码实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| #include <bits/stdc++.h> using namespace std;
long long a[100005]; long long p[100005];
int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int N; cin >> N;
for (int i = 0; i < N; ++i) cin >> a[i]; long long p1 = a[N]; int sign = +1; for (int i = 0; i < N - 1; ++i) { p1 += sign * a[i]; sign = -sign; } p[0] = p1; for (int i = 1; i < N; ++i) { p[i] = 2LL * a[i - 1] - p[i - 1]; } for (int i = 0; i < N; ++i) { if (i) cout << ' '; cout << p[i]; } cout << '\n'; return 0; }
|
一些小细节
- 数据范围最大到 109,N 最大到 105−1,所以 pi 可能很大,要用 long long
- N 是奇数这个条件非常关键,如果 N 是偶数,方程组可能无解或有无穷多解