agc037c Numbers on a Circle

给出 \(n\) 个正整数,绕成一个圈。

现在,第 \(i\) 个值是 \(A_i\). 这些值最后想要变成 \(B_i\).

中间只可以进行一种操作,选一个值 \(i\),其中 \(1\leq i\leq N\).

\(A_i\) 跟新成 \(A_{i-1}+A_i+A_{i+1}\).

\(0\) 个位置就是第 \(n\) 个位置,第 \(n+1\) 个位置就是第 \(1\) 个位置。

是否可以达成这个目标,如果可以达到,需要多少次操作。

\(3\leq n\leq 2\times 10^5, 1\leq A_i,B_i\leq 10^9\)

这个题目其实正向思考非常的不行,因为观察到进行一次操作,两次操作,三次操作之后的模样非常的不可观测,也就是可能性非常多。

但是在思考的过程中发现操作会形成一些峰,对于这些峰顶,会发现形成的可能只能是最后进行了一次上述操作也就是 \(A_i = A_{i-1}+A_i+A_{i+1}\).

考虑再普遍一下,是不是从 \(B\) 推上一步,对于 \(B\) 的峰值,也就是最大值一定是从 \(B_i=B_{i-1}+B_i+B_{i+1}\) 得到的。这样可以直接推出最后一步。

然后,突然发现,对于任何序列,都知道最后一步是什么,也就是相当于 induction 一样,可以一步一步从 \(B\) 推到 \(A\),而且每一步都是确定的。

这样维护一个 priority_queue 来维护最大值就好啦。但其实小细节非常多:首先不能每次只减一次,这样时间复杂度会炸掉。其次不能减到小于 \(A_i\) ,这样什么时候出 priority_queue 就非常看时机了。

tlewawawawawa 了很多次才过了这个题。

但其实分析时间复杂度其实是需要思考一下的。

因为一波操作之后需要改变大小关系,也就是 \(A_i\leq A_{i-1}\) 或者 \(A_i\geq A_{i+1}\) 。那么也就是 \(A_i\) 值至少减半,那么一共的操作波数是 \(O(n\log n)\) 级别的。

时间复杂度: \(O(n\log n\log V)\)

空间复杂度: \(O(n)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+10;
int n,res=0;
int a[N],b[N];
priority_queue<pair<int,int> >pq;
inline int get_pos(int pos){
	if(pos==0)return n;
	if(pos==n+1)return 1;
	return pos;
}
signed main(){
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
	for(int i=1;i<=n;i++)scanf("%lld",&b[i]);
	for(int i=1;i<=n;i++)pq.push(make_pair(b[i],i));
	while(!pq.empty()){
		int pos=pq.top().second;pq.pop();
		if(b[pos]<=a[pos])continue;
		int l=get_pos(pos-1),r=get_pos(pos+1);
		if(b[pos]!=a[pos]&&(b[pos]<=b[l]||b[pos]<=b[r]))continue;
		int cnt=(b[pos]-max(a[pos],max(b[l],b[r])))/(b[l]+b[r]);
		b[pos]-=(b[pos]-max(a[pos],max(b[l],b[r])))/(b[l]+b[r])*(b[l]+b[r]);
		if(b[pos]>max(b[l],b[r])&&b[pos]-b[l]-b[r]>=a[pos]){
			b[pos]-=b[l]+b[r];
			cnt++;
		}
		res+=cnt;
		if(cnt)pq.push(make_pair(b[pos],pos));
	}
	for(int i=1;i<=n;i++)if(a[i]!=b[i])res=-1;
	printf("%lld\n",res);
	return 0;
}
posted @ 2026-05-17 16:44  xyangh  阅读(28)  评论(0)    收藏  举报