加载中...

题解:AT_abc136_e [ABC136E] Max GCD

题意

题目说的不太准确。所以简单概括一下。

给定一个长度为 \(n\) 的数组,对于这个数组,最多可以进行 \(k\) 次操作,操作方法如下:

选择两个数 \(i,j\),让 \(A_i\) 加上 \(1\)\(A_j\) 减去 \(1\)(可能产生负数)。

最终使序列中每一个数都能被答案 \(ans\) 整除,求 \(ans\) 的最大值。

思路

由于每次操作是选择两个数分别加减,可以得出序列的总和 \(sum\) 不变。那么,只要序列中每个数都能被 \(ans\) 整除,那么 \(sum\) 也能被 \(ans\) 整除。

注意到数据范围 \(2 \le n \le 500,1 \le A_i \le 10^6\),说明 \(sum\) 不会太大。想到枚举 \(sum\) 因数。然后判断。考虑贪心。把 \(A_i\)\(ans\) 的余数存到 \(f_i\) 中,从小到大排序。对于余数较小的数字,我们使用减法;对于余数较大的数字,我们使用加法。

使用 \(l\)\(r\) 作为下标,\(x_1\) 记录 \(f_l\)\(x_2\) 记录 \(x - f_r\)。循环判断 \(x_1\)\(x_2\) 的大小。若 \(x_1\) 大,则 cnt += x1, f[r] = f[r] + x1, l++;,若 \(x_2\) 大,则 cnt += x2, f[l] = f[l] - x2, r--;,否则 cnt += x1, l++, r--;

感觉比较清晰了。

代码

#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;

const int N = 505;
int n, a[N], f[N], ans;
long long k, sum;

int check(int x){
	int cnt = 0;
	for(int i = 1; i <= n; i++)
		f[i] = a[i] % x;
	sort(f + 1, f + n + 1);
	int l = 1, r = n;
	while(l <= r){
		int x1 = f[l], x2 = x - f[r];
		if(x1 < x2)
			cnt += x1, f[r] = f[r] + x1, l++;
		else if(x1 > x2)
			cnt += x2, f[l] = f[l] - x2, r--;
		else cnt += x1, l++, r--;
	}
	return cnt;
}

int main(){
	cin >> n >> k;
	for(int i = 1; i <= n; i++)
		cin >> a[i], sum += a[i];
	for(int i = 1; i <= sqrt(sum); i++){
		if(sum % i == 0){
			if(check(i) <= k) ans = max(ans, i);
			if(check(sum / i) <= k) ans = max(ans * 1ll, sum / i);
		}
	}
	cout << ans;
	return 0;
}

posted @ 2025-11-17 18:52  碎碎念的女巫  阅读(3)  评论(0)    收藏  举报