Balanced
赛时做不出来一点,赛后补不出来一点,丢给某个小朋友被一下子秒了,赶紧退役吧。
通过惊人的注意力,我们发现:操作 项各一次,其结果为第 和 项分别增加 、而其余位置分别增加 。在下文中使用“操作 A”指代这一操作。
同时,对所有数操作一遍的结果是所有数等增加 。在下文中使用“操作 B”指代这一操作。
题目并不要求我们的数组最终结果是多少,仅要求所有数都一样。因此,一次操作 A 的结果可以看成“第 和 项减 ,其他位置不变”。
我们还可以对某个数进行 “ 次操作”,即让第 和 项减 ,第 项减 。具体来讲,我们可以对所有数先进行非常多次操作 B(例如 次),然后将要进行负数次操作的位置少进行一些操作即可。
一次操作 A 的结果可以看成“第 和 项减 ,那一次操作 “-A” 的结果可以看成“第 和 项加 。现在,我们只需要实现每次相邻两个数 或 ,让数组相等即可。这样就简单多了!
#include <cstddef>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
istream& fin = cin;
ostream& fout = cout;
using ui = unsigned int;
using uli = unsigned long long int;
using li = long long int;
int main(void) {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
size_t T;
fin >> T;
while (T--) {
size_t n;
fin >> n;
vector<li> a(n);
for (li& i : a) fin >> i;
vector<li> ans(n);
for (size_t i = 1; i + 1 < n; ++i) {
li d = a[i - 1] - a[i];
ans[i] += d;
a[i] += d;
a[i + 1] += d;
}
for (size_t i = n - 3; i < n; i -= 2) ans[i] += a.back() - a.front();
li s = accumulate(ans.begin(), ans.end(), 0ll), s0 = ans[0];
for (size_t i = 1; i < n; i += 2) s0 += ans[i];
for (size_t i = 0; i < n; ++i) {
fout << -(s0 - ans[i]) + (uli)1e18 / 2 << ' ';
s0 = s - s0 + ans[(i + 1) % n];
}
fout.put('\n');
}
return 0;
}