可以发现步数限制把数轴变为了环。环之间不可以交换,环内相邻两点可以交换,然后我们只需要对每个环操作,最后累加。
对于环上的每个石子堆,我们需要将其石子数调整到均值 \(avg\)。因此,我们首先计算每个堆石子相对于 \(avg\) 的偏差,即 \(nowa[i] - avg\)。
因为相邻节点不一定能凑齐 \(avg\),所以我们用 \(b[]\) 数组累积偏差,累积这些偏差后,我们需要选择一个调整量,使得调整所需的总代价最小,那这个数肯定是中位数啊,所以我们环上的每个 \(b[i]\) 都减去中位数然后累加就是这个环的总的操作次数了。
完整代码有注释:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,k;
ll ans;
ll avg;//平均值
ll b[50010];//记录累积偏差值
int nowa[50010];//这个环的第几的点
int a[50010];//这堆石头数
bool vis[50010];//判断这个点是否在环内
ll get_ans(int x){
int t=0;
while(!vis[x]){//已经在环中了
vis[x]=1;
nowa[++t]=a[x];
x+=k;
if(x>n){
x-=n;
}
}
b[1]=0;
for(int i=2;i<=t;i++){
b[i]=b[i-1]+(nowa[i-1]-avg);//累计偏移量
}
sort(b+1,b+1+t);
ll s1=b[(t+1)/2];//取中位数
ll nowans=0;
for(int i=1;i<=t;i++){
nowans+=abs(b[i]-s1);//取最小操作数
}
return nowans;
}
int main() {
ios::sync_with_stdio(false);
cin>>n>>k;
k++;
for(int i=1;i<=n;i++){
cin>>a[i];
avg+=a[i];
}
avg/=n;
for(int i=1;i<=n;i++){
if(vis[i]){//已经在环中了
continue;
}
ans+=get_ans(i);
}
cout<<ans;
return 0;
}
标签:50010,51nod,ll,石子,vis,int,avg,分配
From: https://www.cnblogs.com/sadlin/p/18403122