题解: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;
}


浙公网安备 33010602011771号