原题连接c++
第一思路暴力,时间效率\(O(n^2)\),确定\(T\)此次试都没试,想办法优化吧。
\(O(n^2)\)的效率是由于咱们有两层循环:枚举哪一位移动到队首了,以及计算如今的偏移值。枚举估计是省不了,那么咱们就要想办法把计算偏移值优化到常数级,这样时间效率为\(O(n)\),应该问题不大了。
咱们能够注意到,每次移动时,若是原来\(a[i]<=i\),因为\(a[i]\)对应的\(i\),变大了,因此\(a[i]-i\)负的更多了,绝对值变大了,且每移动一位每一个数的绝对值增大\(1\);相对的,对于\(a[i]>i\),因为\(i\)增大了,绝对值每一个数减少\(1\),所以每次操做咱们只需让\(sumpositive\)减去\(cntpositive\),让\(sumnegative\)加上\(cntnegative\),以后要更新\(cntpositive\)和\(cntnegative\)的值。位于队末的元素比较特殊,它的\(i\)从\(n\)变成了\(1\),须要特殊处理一下。这样的话咱们就把时间效率降到\(O(n)\)了。
有一个小方法须要说一下,就是咱们怎么判断一个差为正的数什么时候转为差为负的数(指小于等于零)。枚举是不可能的,这样时间效率就又回\(n^2\)了。想一下,若是一个数正出来\(x\),那么就必定会在\(x\)轮以后转负(固然是指没有被扔到队首的状况,这时候咱们特殊处理便可),所以咱们在开始输入时就统计出来一个\(count\)数组统计每一个正出来的数的\(x\)值便可。
一些我踩的坑和部分注解在代码里给出。数组
#include<bits/stdc++.h> using namespace std; const int maxn=2000000+3; typedef long long ll; ll n,a[1000000+3],sump,sumn,pos,ans,cntp,cntn,Count[maxn]; //注意maxn不是n的范围,Count的下标是差的值,所以应开到差的最大值 int main(){ scanf("%lld",&n); for(ll i=1;i<=n;i++){ scanf("%lld",&a[i]); if(a[i]<=i){ cntn++; sumn+=i-a[i]; } else{ cntp++; sump+=a[i]-i; Count[a[i]-i]++; } } ans=sump+sumn; pos=0;//注意这里的初始化,必定记得把pos初始化为0,表明不用操做的状况 for(ll i=1;i<=n-1;i++){ sump-=cntp; cntp-=Count[i]; sumn+=cntn; cntn+=Count[i]; sumn-=n+1-a[n-i+1]; cntn--; if(a[n-i+1]>1){ Count[a[n-i+1]-1+i]++; sump+=a[n-i+1]-1; cntp++; } else cntn++; if(sumn+sump<ans){ ans=sumn+sump; pos=i; } } printf("%lld %lld",ans,pos); return 0; }
幸甚至哉,歌以咏志。优化