hdu 6237

来源:互联网 发布:网络基础技术视频教程 编辑:程序博客网 时间:2024/06/05 00:58

(贪心)
题意:给定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 longusing 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;}
原创粉丝点击