(贪心)
题意:给定
n(n<105)
堆石子,每堆石子有
ai(ai<105)
个,每次操作可以将一个石子从一堆移动到另一堆,求最少的操作次数,使得存在一个数
x(x>1)
,使得每一堆石子均能被
x
整除。
思路:依题意可知,
吐槽:题目难点在于如何贪心,如果同时考虑拿走多少个石子和需要补多少个石子,就会想复杂。所以要简化条件,只考虑一方面就可以求解。
代码:
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define LL long long
using namespace std;
const int maxn = 100010;
const LL inf = 1000000000000;
LL a[maxn], t[maxn];
LL fac[maxn], cnt;
void get_fac(LL x) {
LL t = x; cnt = 0;
for(LL i=2; i*i<=t; i++) if(t%i == 0) {
while(t%i == 0) t /= i;
fac[cnt++] = i;
}
if(t > 1) fac[cnt++] = t;
}
int main() {
LL T, n;
scanf("%lld",&T);
while(T --) {
scanf("%lld",&n);
LL sum = 0;
for(LL i=1; i<=n; i++) {
scanf("%lld",&a[i]);
sum += (LL)a[i];
}
sort(a+1, a+n+1);
get_fac(sum);
LL ans = inf;
for(LL i=0; i<cnt; i++) {
LL x = fac[i], res = 0, all = 0;
for(LL j=1; j<=n; j++) {
t[j] = a[j] % x;
all += t[j];
}
sort(t+1, t+n+1);
for(LL j=n; j>=1; j--) if(all > 0) {
res += x-t[j];
all -= x;
}
ans = min(ans, res);
//printf("x:%lld res:%lld\n",x,res);
}
printf("%lld\n",ans);
}
return 0;
}