【luogu AT5160】Numbers on a Circle(贪心)(堆)

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;
}

猜你喜欢

转载自blog.csdn.net/weixin_43346722/article/details/120999948
今日推荐