CCPC.2017哈尔滨站 H(思维)

题目链接:传送门

思路:
1、求出sum的所有质因子c[i] ( 1<=i<=tot )
2、判断如果当前x = c[i]时,求出当前x下所需要的最小和ans
3、最小和ans的求法:
求出1~n中a[i]对x取模后的数组b[i],对b[i]进行排序,
分别取出b的左右两个端点,如果当前b[l] + b[r] > x,则以较小的代价ans += (x - b[r])将b[r]化为x,同时削减b[l] -= (x - b[r]);
如果b[l] + b[r] <= x,增加b[r]的值,让b[r]的值尽可能变大。
(这样可以让b[l]尽可能小,让b[r]尽可能大,同时保证每次ans增加的值最小)。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+10;
int n,tot;
ll b[N],a[N],c[N];
void fj(ll sum)
{
    tot = 0;
    ll tp = (ll)sqrt(1.0*sum);
    for(ll i=2;i<=tp;i++){
        if(sum%i == 0){
            c[++tot] = i;
            while(sum%i == 0){
                sum /= i;
            }
        }
    }
    if(sum > 1LL){
        c[++tot] = sum;
    }
}
ll f(ll x)
{
    ll ans = 0;
    for(int i=1;i<=n;i++) b[i] = a[i]%x;
    sort(b+1,b+1+n);
    int l = 1,r = n;
    while(l<r){
        if(b[l] + b[r] > x){
            //a[l] decrease
            ans += (x - b[r]);
            b[l] -= (x - b[r]);
            r--;
        }
        else{
            //a[r] increase
            ans += b[l];
            b[r] += b[l];
            l++;
        }
    }
    return ans;
}
int main(void)
{
    int T;
    cin>>T;
    while(T--){
        cin>>n;
        ll sum = 0,mx = 0;
        for(int i=1;i<=n;i++) cin>>a[i],sum += a[i],mx = max(mx,a[i]);
        fj(sum);
        //最坏情况,把所有物品放到mx上面
        ll ans = sum - mx;
        for(int i=1;i<=tot;i++){
            ans = min(ans,f(c[i]));
        }
        cout<<ans<<endl;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值