可以发现步数限制把数轴变为了环。环之间不可以交换,环内相邻两点可以交换,然后我们只需要对每个环操作,最后累加。
对于环上的每个石子堆,我们需要将其石子数调整到均值 \(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;
}