CF传送门
洛谷传送门
解题思路
很容易发现,对于每一次移动,除了最后一位,每一个数对答案的变化的贡献只有两种情况:
- 若a[i]>=i,对答案的贡献是+1
- 若a[i]<i,对答案的贡献是-1
所以我们可以预处理出每个时刻从a[i]<i到a[i]>=i的数有多少个,然后动态维护cnt1和cnt2(分别记录当前-1的和+1的数字有几个)。
一定要注意最后一位的处理,很显然最后一位一定是从cnt2中移动到了cnt1中,所以别忘记cnt1++,cnt2--。
细节比较多,一定要注意细节。
AC代码
1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstdio> 5 #include<cstring> 6 #include<cstdlib> 7 #include<queue> 8 #include<set> 9 #include<map> 10 #include<vector> 11 #include<iomanip> 12 #include<ctime> 13 #include<stack> 14 using namespace std; 15 const int maxn=1000005; 16 int n,a[maxn],k,t[maxn],cnt1,cnt2; 17 long long res,ans; 18 int main() 19 { 20 cin>>n; 21 for(int i=1;i<=n;i++) cin>>a[i]; 22 for(int i=1;i<=n;i++){ 23 int x=a[i]-i; 24 if(x>0){ 25 res+=x; 26 t[x]++; 27 cnt1++; 28 }else{ 29 res-=x; 30 t[n+x]++; 31 cnt2++; 32 } 33 } 34 ans=res; 35 for(int i=1;i<=n;i++){ 36 res=res-cnt1+cnt2; 37 cnt1=cnt1-t[i]; 38 cnt2=cnt2+t[i]; 39 res=res-abs(a[n-i+1]-n)+abs(a[n-i+1]-1)-1; 40 cnt1++; 41 cnt2--; 42 if(ans>res) ans=res,k=i; 43 } 44 cout<<ans<<" "<<k; 45 return 0; 46 }