【luogu AT5160】Numbers on a Circle(貪心)(堆)
阿新 • • 發佈:2021-10-27
給你一個長度為 n 的環,你每次操作可以把一個位置加上它兩邊的值。
然後給你初始狀態和目標狀態,問你至少要多少次操作才能實現,或者輸出無法實現。
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; }