原題連接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; }
幸甚至哉,歌以詠志。優化