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
*/

 

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