hdu 6237

(贪心)
题意:给定 n(n<105) 堆石子,每堆石子有 ai(ai<105) 个,每次操作可以将一个石子从一堆移动到另一堆,求最少的操作次数,使得存在一个数 x(x>1) ,使得每一堆石子均能被 x 整除。

思路:依题意可知, x 必须为 Nn=1ai 的因子,于是我们先将 x 进行质因数分解,然后枚举每一个质因数。对于每一个质因数 fac[i] ,求出每堆石子拿走 t[j] 才能被 fac[i] 整除,排序,然后从大到小贪心,把小的 t[j] 往大的上补,求出最少需要移动几个石子。

吐槽:题目难点在于如何贪心,如果同时考虑拿走多少个石子和需要补多少个石子,就会想复杂。所以要简化条件,只考虑一方面就可以求解。

代码:

#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;
}
发布了40 篇原创文章 · 获赞 44 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/Site1997/article/details/78868904