[CF819B] Mister B and PR Shifts

題目

原題連接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;
}

幸甚至哉,歌以詠志。優化

相關文章
相關標籤/搜索