下标默认是在 \(\bmod\ n\) 意义下的。
考虑到如果 \(a_i > b_i\) 那么不可能只操作 \(a_{i - 1}\) 使得 \(a_i\) 合法,因为这只增不减。
于是这说明当 \(a_i > b_i\) 时一定会操作 \(a_i\) 使得 \(a_i\le b_i\)。
但是同时如果 \(b_i - a_i\) 太大了,\(a_{i - 1}\) 就不一定能操作完了。
于是贪心的,当 \(a_i > b_i\) 时,让调整后的 \(b_i - a_i\) 尽量小,就能给后面的步骤留出更多的调整空间。
所以若 \(a_i\bmod 2 = b_i\bmod 2\),则操作 \(a_i\) 使得 \(a_i\leftarrow b_i\);否则操作 \(a_i\) 使得 \(a_i\leftarrow b_i - 1 + 2[b_i = 0]\)(当 \(b_i = 0\) 时,因为需要满足时刻 \(a_i\ge 0\),只能使 \(a_i = 1\))。
根据这个贪心的思想,每一步都在使得 \(a_i\) 能够更接近 \(b_i\)。
所以一直这样操作下去直到无法操作,如果满足 \(\forall i\in [1, n], a_i = b_i\) 则合法,否则不合法。
(可以手玩一下不合法的局面,能发现此时操作任意一个 \(a_i\) 后 \(a_i\) 至少也会 \(-1\),只会变小,之后就肯定不可能变大成 \(b_i\) 了。)
那么接下来考虑快速模拟这个过程了。
首先可以先模拟一圈(\(1\sim n\) 做一次贪心),那么能发现此时的 \(a_i\) 是比较有性质的。
具体来说,\(\forall i\in [2, n]\),要么 \(a_i = 1\) 且 \(b_i = 0\),要么 \(a_i\le b_i\)。
这是因为 \(2\sim n\) 按顺序调整后 \(i - 1\) 没有再次进行操作,所以依然保持原样。
且此时 \(a_1\le 2V\),舍弃掉 \(\bmod\ 2\) 后的余数的损失,考虑距离 \(1\) 为 \(d\) 那么给到 \(a_1\) 的贡献至多为 \(\frac{V}{2^d}\),那么有 \(\sum\limits_{i = 0}^{n - 1} \frac{V}{2^i}\le 2V\)。
那么操作 \(1\) 后至多 \(a_2\) 得到 \(\lfloor\frac{a_1}{2}\rfloor = V\) 的增量。
再往后,令当前在位置 \(i\),\(i - 1\) 给 \(a_i\) 的增量为 \(x\),考虑此时满足要么 \(a_i = 1\) 且 \(b_i = 0\),要么 \(a_i\le b_i\),所以 \(i\) 给到 \(i + 1\) 的增量肯定不会超过 \(\lfloor\frac{x + 1}{2}\rfloor\)。
那么可以知道的是,在 \(\mathcal{O}(\log V)\)(精确值应当是 \(31\))轮后,增量 \(x\) 就会变为 \(1\)。
此时考虑若增量为 \(1\) 时 \(a_i = 1, b_i = 0\),或者 \(a_i = b_i\not = 0\) 时带给下一轮的增量依然为 \(1\)。
首先考虑 \(a_i = 1, b_i = 0\) 这种情况,那么在得到增量并进行操作后,\(a_i = b_i = 0\),等再转过来时因为能产生的增量 \(\le 1\),那么这个位置已经产生不了增量了,于是最多转 \(n\) 次就会结束。
然后考虑 \(a_i = b_i\not = 0\) 这种情况,那么在得到增量并进行操作后,\(a_i = b_i - 1\),一样的等再转过来时这个位置一定产生不了增量,于是最多转 \(n\) 次就会结束。
综上,能够知道的是在增量 \(x = 1\) 后最多转一圈,也就是继续往后模拟 \(n\) 次后一定会终止。
于是可以知道,最多 \(2n + \mathcal{O}(\log V)\) 次模拟后就不会产生增量,\(a_i\) 就不会发生改变了。
直接模拟即可,时间复杂度 \(\mathcal{O}(n + \log V)\)。
#include<bits/stdc++.h>
constexpr int maxn = 1e6 + 10;
int a[maxn], b[maxn];
int main() {int n;scanf("%d", &n);for (int i = 0; i < n; i++) scanf("%d%d", &a[i], &b[i]);for (int T = 0; T < n + 33 + n; T++) {int i = T % n, j = (i + 1) % n;if (a[i] < b[i]) continue;if (! b[i]) {a[j] += a[i] / 2, a[i] %= 2;} else {int d = (a[i] - b[i] + 1) / 2;a[j] += d, a[i] -= d * 2;}}for (int i = 0; i < n; i++) {if (a[i] != b[i]) {return puts("No"), 0;}}return puts("Yes"), 0;
}