AT_arc079_b [ABC068D] Decrease (Contestant ver.) 题解

一道绿题写了一个半小时……

题目

看到这道题,直接一看,\(N=1\)\(a_1=x\) 就完事了?交了发现题面写了 \(2 \le N\)……

不难发现,无论 \(N\) 是多少,每次 \(N-1\) 个数 \(+1\),一个数 \(-N\),总和每次 \(-1\)。那么总和至少为 \(K\) 才行。

直接想 \(N=2\) 的,因为总和至少为 \(2\) 才能操作,假设 \(a_1=K+1\)。然后有可能 \(\begin{cases}a_1=1\\a_2=1\end{cases}\),此时总和 \(\ge 2\) 但仍然不能操作,于是这种情况 \(a_2=1\) 即可。交上去发现又 WA 了。一看题面:\(K \le 50 \times 10^{16}\),但 \(a_i \le 10^{16}+1000\)

首先先写个代码,来看给定 \(N,a\) 时的 \(K\) 值(即这场比赛下一道题的暴力):

#include<bits/stdc++.h>
using namespace std;
namespace estidi{
	int a[53];
	int main(){
		int n,x=0,cnt,ans=0;
		cin>>n;
		for(int i=1;i<=n;i++)
			cin>>a[i];
		while(1){
			cnt=0;
			for(int i=1;i<=n;i++)
				if(a[cnt]<a[i])
					cnt=i;
			if(a[cnt]<n)
				break;
			ans++;
			a[cnt]-=n+1;
			for(int i=1;i<=n;i++)
				a[i]++;
		}
		cout<<ans<<endl;
		for(int i=1;i<=n;i++)
			cout<<a[i]<<" ";
		return 0;
	}
}
int main(){
	estidi::main();
	return 0;
}

因为 \(N \le 50\),而 \(K\) 又专门把 \(50\) 提出来,没写 \(5\times 10^{17}\),自然想到最终答案 \(N=50\)\(a_i \le \frac{K}{50}+1000\)

先考虑 \(N=2\) 时怎么使 \(a_i\)\(\frac{K}{2}\) 附近。乱找规律发现当 \(a_1=a_2=x+1\) 时,答案为 \(2x\)。再总结发现 \(a_1=a_2=\dots=a_N=x+N-1\) 时,答案为 \(x\times N\)

但这样还只能得出 \(50\mid x\) 时的结论,继续观察,再次假设 \(N=2\),发现当 \(\begin{cases}a_1=x\\a_2=x+2\end{cases}\) 时,答案为 \(2x+1\)。但这个结论不好推至 \(N=50\) 时的情况,于是考虑 \(N=3\) 时的来找规律。发现 \(\begin{cases}a_1=x+1\\a_2=x+1\\a_3=x+4\\K=3x+1\end{cases}\)\(\begin{cases}a_1=x\\a_2=x+4\\a_3=x+4\\K=3x+2\end{cases}\)

后面当时是怎么乱想的我忘了,反正式子推错又 WA 了好几次。现在我发现:\(\begin{cases}a_1=x+N+1\\a_2=x+N+1\\\dots\\a_y=x+N\\a_{y+1}=x+N-1-y\\\dots\\a_N=x+N-1-y\\K=Nx+y\end{cases}\)\(N\) 取 50 即可。

代码:

#include<bits/stdc++.h>
using namespace std;
namespace estidi{
	int main(){
		long long k,kk;
		scanf("%lld",&k);
		kk=k%50;
		k/=50;
		printf("50\n");
		for(int i=1;i<=kk;i++)
			printf("%lld ",k+51);
		for(int i=kk+1;i<=50;i++)
			printf("%lld ",k+49-kk);
		return 0;
	}
}
int main(){
	estidi::main();
	return 0;
}
posted @ 2025-02-14 16:38  123asdf123  阅读(6)  评论(0)    收藏  举报