究竟是谁在上分(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;
}