究竟是谁在上分(CF2124E)

传送门

纯难啊,感觉哪怕猜到了 \(17\) 次是骗人的还是不太好想。究竟是谁在上分。

官方做法。

先判无解

首先注意到每次 \(a\) 的总和 \(sum\) 会减去一个偶数。那么有解的第一个条件就是总和 \(sum\) 为偶数。

然后注意到,设 \(mx\)\(a\) 中最大值,那么如果有 \(mx>(sum-mx)\)\(2mx>sum\),可以发现无论如何也消不掉。所以有解的第二个条件是 \(2mx\le sum\)这一个条件是下文的重点。

正片开始

如果你被题目里的 \(17\) 次给骗了,并固执地以为正解是 \(\log n\) 相关,那你就输完了。正解最多只要 \(3\) 次,且可以合并成 \(2\) 次。

n 为 3


首先一种特殊情况是 \(a_1=a_2+a_3\) 或者 \(a_1+a_2=a_3\)。这个时候非常显然,答案就是 \(1\) 次。

判掉这个后考虑从 \(n=3\) 时的另外一种特殊情况入手(想到这个不太自然)。当 \(a_1+a_3=a_2\) 时,显然的构造是第一次将数组变成 \([0,a_3,a_3]\),第二次消去两个 \(a_3\)

然后考虑 \(n=3\) 时的一般情况。我们考虑将一般的情况转换为上述的特殊情况,即第一次操作将 \(a_1\)\(a_3\) 减去 \(w\),使得 \((a_1-w)+(a_3-w)=a_2\)。显然 \(w=\frac{a_1+a_3-a_2}{2}\)

由于 \(sum\) 为偶数,所以 \(a_1+a_3-a_2\)\(sum-2a_2\) 也为偶数,得到的 \(w\) 一定是个整数。同时还可以证明 \(w\) 不大于 \(a_1,a_3\):钦定 \(a_1\le a_3\),即证明 \(\frac{a_1+a_3-a_2}{2}\le a_1\),得到 \(a_1+a_2\ge a_3\),这显然是有解的必要条件,于是得证。

于是通过 \(3\) 次操作我们成功解决了 \(n=3\) 的一般情况。如果考虑优化成 \(2\) 次的话可以将前两次操作合并,即第一次操作直接将 \(a_1\)\(0\)\(a_2\) 减去 \(a_1-w\)\(a_3\) 减去 \(w\)

\(n\) 任意


知道了 \(n=3\) 怎么做后考虑推广到任意 \(n\)。 考虑将数组划分成三段,从左到右每段的和分别为 \(x,y,z\),其中须满足 \(x,y,z\le \frac{sum}{2}\),那么就成功转换为了 \(n=3\) 的情况。

可以发现,在有解的条件下,总是存在一个分界点 \(p\),满足 \(\sum_{i=1}^{p-1}a_i<\frac{sum}{2}\)\(\sum_{i=1}^{p}a_i\ge\frac{sum}{2}\),那么令三段分别为 \([1,p-1]\)\([p,p]\)\([p+1,n]\) 即可满足条件。然后只需要按照 \(n=3\) 的构造去做即可。

code

优化成了 \(2\) 次的实现,注意全程开 ll。

#include <bits/stdc++.h>
//taskkill /f /im 未命名1.exe
#define ED cerr<<endl;
#define TS cerr<<"I AK IOI"<<endl;
#define cr(x) cerr<<x<<endl;
#define cr2(x,y) cerr<<x<<" "<<y<<endl;
#define cr3(x,y,z) cerr<<x<<" "<<y<<" "<<z<<endl;
#define cr4(x,y,z,w) cerr<<x<<" "<<y<<" "<<z<<" "<<w<<endl;
#define print(a,l,r) for(int i=l;i<=r;++i) cerr<<a[i]<<' ';puts("");
#define popcnt __builtin_popcount
#define all(s) s.begin(),s.end()
#define bstring basic_string
//#define add(x,y) (x+=y)%=mod
#define pii pair<int,int>
#define epb emplace_back
#define pb push_back
#define mk make_pair
#define ins insert
#define fi first
#define se second
#define int long long
//#define ull unsigned long long
using namespace std;
const int N=2e5+5,INF=2e9,mod=1e9+7;
int t,n,m;
int a[N]; 

void sol() {
	scanf("%lld",&n);int sum=0,mx=0;
	for(int i=1;i<=n;++i) {
		scanf("%lld",&a[i]);
		sum+=a[i],mx=max(mx,a[i]);
	}
	if((sum&1)||mx*2>sum) {
		puts("-1");return;
	}
	int p=1,x=0;
	for(int i=1;i<=n;++i) {
		x+=a[i];
		if(x>sum/2) {
			p=i,x-=a[i];break;
		}
	}
	if(x==sum/2) {
		printf("1\n");
		for(int i=1;i<=n;++i) {
			printf("%lld ",a[i]);
		}
		puts("");return;
	}
	printf("2\n");
	int w=(sum-2*a[p])/2,v=x-w;
	for(int i=1;i<p;++i) {
		printf("%lld ",a[i]),a[i]=0;
	}
	printf("%lld ",v),a[p]-=v;
	for(int i=p+1;i<=n;++i) {
		int qwq=min(w,a[i]);
		printf("%lld ",qwq);
		a[i]-=qwq,w-=qwq;
	}
	puts("");
	for(int i=1;i<=n;++i) {
		printf("%lld ",a[i]);
	}
	puts("");
}

signed main()
{
	scanf("%lld",&t);
	while(t--) {
		sol();
	}
	return 0;
}

posted @ 2025-07-21 20:23  Oier_szc  阅读(7)  评论(0)    收藏  举报