AtCoder Beginner Contest 268-E题解
题目大意
有\(n\)个人,编号为\(0,1,2,3,\cdots,n-1\),围成一个圈,有一个排列,表示在第\(i\)个人手中的数是\(P_i\)。
每次操作,第\(i\)个人把手中的数给\((i+1)mod\ n\)。第\(i\)个人的不满意度为\(i\)这个数离他的距离。
问不满意度之和最小为多少
题解
分析
由于是绕圈着的,所以第\(i\)人离\(i\)这个数的距离可以描述为两种状态
- \(i\)这个数逐渐离\(i\)这个人靠近
- \(i\)这个数逐渐离\(i\)这个人远离
由于所有数的移动速度都为\(1\),所以所有点的这两个状态都满足先进先出的原则。
所以我们可以用两个队列来维护处在这两种状态下的数。
记得处理一开始的入队顺序便可以通过本题。
code
#include<bits/stdc++.h>
#define rg register
#define fre(x)freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
using namespace std;
typedef long long LL;
typedef long double LD;
typedef double db;
typedef unsigned long long uLL;
const db Pi=acos(-1);
queue<int> q[2];
vector<pair<int,int> > p[2];
int a[200005];
int main(){
LL now=0,ans;
int n;scanf("%d",&n);
for(int i=0,x;i<n;i++){
scanf("%d",&x);
int l=(x-i+n)%n;
int r=(i-x+n)%n;
p[l>r].push_back({min(l,r),x});
now+=min(l,r),a[x]=i;
}
sort(p[0].begin(),p[0].end());
for(int i=0;i<p[0].size();i++)
q[0].push(p[0][i].second);
sort(p[1].rbegin(),p[1].rend());
for(int i=0;i<p[1].size();i++)
q[1].push(p[1][i].second);
ans=now;
for(int i=1;i<n;i++){
while(!q[0].empty()){
int u=q[0].front();
int v=(a[u]+i)%n;
int l=(u-v+n)%n;
int r=(v-u+n)%n;
if(l<=r)break;
q[0].pop(),q[1].push(u);
}
while(!q[1].empty()){
int u=q[1].front();
int v=(a[u]+i)%n;
int l=(u-v+n)%n;
int r=(v-u+n)%n;
if(r<l)break;
q[1].pop(),q[0].push(u);
l=(l+1)%n,r=(r+n-1)%n;
now-=r,now+=l;
}
now-=q[0].size(),now+=q[1].size();
ans=min(ans,now);
}printf("%lld",ans);
system("pause");
return 0;
}

浙公网安备 33010602011771号