Atcoder ABC313_C-Approximate Equalization II

AT_ABC313_C-Approximate Equalization II


>> 没想到还有Approximate Equalization I !!:AT_ABC307_G

Description:

  • 给定一个整数序列 \(A=(A_1,A_2,···,A_n)\),可以做以下操作任意次(可能为0):选择一个整数对 \((i,j)\) \((1\leq i,j\leq n)\),使得\(A[i]-\)=\(1\), \(A[j]+\)=\(1\),求出使得数列 \(A\) 中的 \(max-min \leq 1\) 所需的最少操作次数。

Constraints

  • \(1 \leq n \leq 2 \times 10^5\)
  • \(1 \leq A_i \leq 10^9\)

Analysis:

  • 最容易想到的就是贪心策略,为了让最后的序列尽可能趋同,不妨每次让最大值减小,最小值增大,很明显会超时,故排除。
  • 既然无法通过模拟逐步去逼近,那不妨尝试直接构造终态的数列:我们发现,无论如何操作,由于正负相抵,\(\sum{A_i}\) 恒为定值,故最终必然逼近平均值 \(ave\),进一步考虑细节,无法整数得到的余数个数即为在平均值基础上\(+1\)的个数,即最终数列由 \(ave\)\(ave+1\)组成。(当然,其分别的个数 \(x\),\(y\) 我们也可以通过方程组求解)

\[\left\{ \begin{aligned} &x+y = n \\ &x\times res+y\times (res+1)=sum=\sum{A_i} \end{aligned} \right. \]

  • 我们已经构造出终态数列 \(B\),和排序后的 \(A\) 相对应,即可求出总共的加减次数,除以二即为操作次数。
    \(ans =\) \(\frac{\sum_{k=1}^{N} |A_k-B_k|}{2}\)

Solution:

void solve() {
	int n; cin >> n;
	vector<int> a(n);
	ll sum = 0;
	for(int i=0;i<n;i++) {
		cin >> a[i];
		sum += a[i];
	}
	ll ave = sum / n; 
	sort(a.begin(),a.end()); // 排序

	vector<ll> b(n,ave); //初始化构造的序列均为平均值
	
	for(int i=0;i<sum%n;i++) {
		// 进行余数个次的补加1,注意下标运算,从b.end向前操作
		b[n-1-i]++; 
	}
	ll ans = 0;
	for(int i=0;i<n;i++) {
		ans += abs(a[i]-b[i]);
	}
	cout << ans/2 << endl;
	return ;
}
Show Code(解方程 | 赛中)
ll a[maxn];
ll res;
void solve() {
	int n; cin >> n;
	for(int i=1;i<=n;i++) {
		cin >> a[i];
		res += a[i];
	}
	ll ave = res / n;
	sort(a+1,a+1+n);
	if(res % n == 0) {
		cout << ave-a[1] << endl;
		return;
	}

	ll x = (ave+1)*n-res;
	ll y = res-ave*n;
	ll ans=0;
	for(int i=1;i<=x;i++) {
		if(a[i] >= ave+1) break;
		ans += (ave-a[i]);
	}
	for(int i=x+1;i<=n;i++) {
		if(a[i] >= ave+1) break;
		ans += (ave+1-a[i]);
	}
	cout << ans << endl;
	return ;
}
posted @ 2023-08-07 15:58  Trilliverse  阅读(31)  评论(0编辑  收藏  举报