Numbers on a Circle
题目链接:luogu AT5160
题目大意
给你一个长度为 n 的环,你每次操作可以把一个位置加上它两边的值。
然后给你初始状态和目标状态,问你至少要多少次操作才能实现,或者输出无法实现。
思路
考虑反过来,变成你每次会减去两边的值。
那这个有什么用呢,你会发现每次只会有一些点可以做。
(它一定要大于它两边的和)
而且它们之间一定有间隔,也就是说它们之间谁先做无关。
那我们就可以直接暴力用堆枚举它们,然后直接减。
那你一次一次减当然是不可以的,所以我们要直接减到不能减。
(或者减到目标,但如果减不到目标而且直接减会比目标小就无解)
最后判一下是否全部都减好了就可行了。
代码
#include<queue>
#include<cstdio>
#define ll long long
using namespace std;
int n, a[200001], b[200001];
priority_queue <pair<int, int> > q;
bool ok[200001];
ll ans;
bool up(int now) {
if (ok[now]) return 0;
return b[now] > b[(now + 1) % n] + b[(now - 1 + n) % n];
}
int main() {
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d", &a[i]);
for (int i = 0; i < n; i++)
scanf("%d", &b[i]);
for (int i = 0; i < n; i++)
if (up(i)) q.push(make_pair(b[i], i));
while (!q.empty()) {
int now = q.top().second;
q.pop();
int to = b[now] % (b[(now + 1) % n] + b[(now - 1 + n) % n]);
if (to > a[now]) {
ans += b[now] / (b[(now + 1) % n] + b[(now - 1 + n) % n]); b[now] = to;
if (up((now + 1) % n)) q.push(make_pair(b[(now + 1) % n], (now + 1) % n));
if (up((now - 1 + n) % n)) q.push(make_pair(b[(now - 1 + n) % n], (now - 1 + n) % n));
}
else {
if ((b[now] - a[now]) % (b[(now + 1) % n] + b[(now - 1 + n) % n])) {
printf("-1"); return 0;
}
ans += (b[now] - a[now]) / (b[(now + 1) % n] + b[(now - 1 + n) % n]);
b[now] = a[now];
if (up((now + 1) % n)) q.push(make_pair(b[(now + 1) % n], (now + 1) % n));
if (up((now - 1 + n) % n)) q.push(make_pair(b[(now - 1 + n) % n], (now - 1 + n) % n));
ok[now] = 1;
}
}
for (int i = 0; i < n; i++)
if (a[i] != b[i]) {
printf("-1"); return 0;
}
printf("%lld", ans);
return 0;
}