题目
题意
给 n n n(1e5)个数 a [ i ] a[i] a[i](1e6),每次可以将 a [ i ] − 1 a[i]-1 a[i]−1,使得 a [ i + 1 ] + 1 a[i+1]+1 a[i+1]+1或者 a [ i − 1 ] + 1 a[i-1]+1 a[i−1]+1,求最少操作几次,使得每个 a [ i ] a[i] a[i]要么是0,要么都是某个数k(不能为1)的倍数。
思路
s
l
o
v
e
(
X
)
slove(X)
slove(X)>
s
o
l
v
e
(
X
的
因
子
)
solve(X的因子)
solve(X的因子),所以只要对
n
n
n的质因子作为
k
k
k。复杂的降为
O
(
n
l
o
g
1
e
11
)
O(nlog1e11)
O(nlog1e11)
然后对于某一个
k
k
k,可以将所有的
a
[
i
]
a[i]
a[i]先%
k
k
k(等效),然后每
k
k
k个数合并到最中间那个数。
然后就是代码问题了。
/*
Author: Rshs
Time: 2019-11-21-21.33
*/
#include<bits/stdc++.h>
using namespace std;
#define FI first
#define SE second
#define LL long long
#define MP make_pair
#define PII pair<int,int>
#define SZ(a) (int)a.size()
const double pai = acos(-1);
const double eps = 1e-8;
const LL mod = 1e9+7;
const int MXN = 1e6+5;
int a[MXN];
LL b[MXN];
LL f(LL div,LL sgma,int n){
LL aaa=0,sss=0;
for(int i=1;i<=n;i++) b[i]=a[i]%div;
for(LL i=1;i<=n;){
LL l=i,ti=i,sum=0;
sum+=b[i];
while(sum<div&&i<n) i++,sum+=b[i];//第一个>=div的位置
LL ss=0;
ss+=b[ti];
while(ss<div/2+(div%2==1)&&ti<n) ti++,ss+=b[ti]; //中间的数的位置
for(LL j=l;j<ti;j++) aaa=aaa+b[j]*abs(ti-j);
for(LL j=ti+1;j<i;j++) aaa=aaa+b[j]*abs(ti-j);
aaa=aaa+(b[i]-(sum-div))*abs(i-ti);
b[i]=sum-div;
if(i==n) break;
}
return aaa;
}
int main(){
int n;cin>>n;
LL sgma=0;
for(int i=1;i<=n;i++)scanf("%d",&a[i]),sgma+=(LL)a[i];
if(sgma==0) return puts("0"),0;
if(sgma==1) return puts("-1"),0;
LL ans=LLONG_MAX,div=2,tsgma=sgma;
for(;div*div<=tsgma;div++){
if(tsgma%div==0){
ans=min(ans,f(div,sgma,n));
}
while(tsgma%div==0) tsgma/=div;
}
if(tsgma!=1){
ans=min(ans,f(tsgma,sgma,n));
}
if(ans==LLONG_MAX) ans=-1;
cout<<ans<<'\n';
return 0;
}