Codeforces 1255 div2 E1 Send Boxes to Alice (Easy Version)

題目描述

給你一個序列,ai表示i位置有多少個糖果,每次你可以將一個位置i的一個糖果給位置i+1或者位置i-1(如果存在的話),現在你需要對糖果進行移動,對於每個有糖果的堆,糖果的數量必須是一個數k(k>1)的倍數,允許空堆的存在,問你最少需要移動多少步?

思路

假設n堆中有m個爲1的糖果,也就是總共爲m個糖果,如果可以不全部彙總,我肯定可以將m個糖果分爲k堆,k爲m的因子,比如1 1 0 0 1 1 0 0 1 1,有6個糖果,當k=2時兩兩化成一堆最優。

但是k我們不能確定,比如1 1 1 0 0 0 0 1 1 1 ,這樣當k=3時纔是最優的,所以我們枚舉m的因子k,對於每個因子k,我們每次合併肯定拿前k個合併最優,暴力枚舉一下,用中位數計算答案就好了。

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;

const int maxn=1e5+10;
int a[maxn];
vector<int>G;
int n;
ll calculate(int x){
    //printf("debug %d ",x);
    if(x==1)return 1e18;
    ll ans=0;
    int pos=0;
    for(int i=0;i<G.size();){
        vector<int>v;
        int cnt=x;
        for(int j=pos+1;j<=n;j++){
            if(a[j]){
                v.push_back(j);
                cnt--;
            }
            if(!cnt){
                pos=j;
                break;
            }
        }
        ll center=0;
        if(v.size()&1){
            center=v[v.size()/2];
        }
        else{
            center=(v[v.size()/2-1]+v[v.size()/2])/2;
        }
        for(int j=0;j<v.size();j++){
            ans+=abs(1ll*v[j]-center);
        }
        i+=x;
    }
    //printf("ans %lld\n",ans);
    return ans;
}
signed main(){
    scanf("%d",&n);
    int sum=0;
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        sum+=a[i];
        if(a[i])G.push_back(i);
    }
    if(sum<=1){
        puts("-1");
        return 0;
    }
    ll ans=1e18;
    for(int i=1;i*i<=sum;i++){
        if(sum%i==0){
            int a=i;
            ans=min(ans,calculate(a));
            if(sum/a!=a){
                int b=sum/a;
                ans=min(ans,calculate(b));
            }
        }
    }
    printf("%lld\n",ans);
    return 0;

}
/*
10
1 1 1 0 0 0 0 1 1 1
*/

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章