1. 程式人生 > 實用技巧 >CF819B Mister B and PR Shifts(思維)

CF819B Mister B and PR Shifts(思維)

做這題細節比較多,要想清楚實際的含義

首先我們肯定是想著列舉看看把哪些提到最前面

對於這題我們發現我們要維護的有兩種情況,一種是相減小於0,一種是相減大於0

因此我們分兩種情況討論,並且注意狀態的變化,具體細節看程式碼註釋

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll> pll;
const int N=2e6+10;
const int inf=0x3f3f3f3f;
const int
mod=1e9+7; ll a[N],sign[N];//sign表示移動i次變成第二類點的個數 int main(){ ios::sync_with_stdio(false); int n; cin>>n; int i; ll pcnt=0,pres=0; ll ncnt=0,nres=0; for(ll i=1;i<=n;i++){ cin>>a[i]; if(a[i]<=i){ ncnt++; nres+=(i-a[i]); }
else{ sign[a[i]-i]++; pcnt++; pres+=(a[i]-i); } } ll ans=pres+nres; ll k=0; for(i=1;i<n;i++){ pres-=pcnt;//第一類答案都減 pcnt-=sign[i];//失去變成第二類的 nres+=ncnt;//第二類答案都是加 ncnt+=sign[i];//多出來的第二類 ll x=a[n-i+1];//最後一位移到隊首
ncnt--; nres-=(n+1-x);//因為先行計算,導致最後一位到了n+1處,我們先減去他的貢獻後把他移到第一位 if(x>1){ pcnt++; pres+=(a[n-i+1]-1); sign[x-1+i]++;//如果他又變成了第二類點,那麼要加上他之前移動的i步再計算 } else{ ncnt++; } if(ans>pres+nres){ ans=pres+nres; k=i; } } cout<<ans<<" "<<k<<endl; return 0; }
View Code