1. 程式人生 > >2018年10月18日提高組 T2 健美貓

2018年10月18日提高組 T2 健美貓

大意

給定一個長度為nn的序列SS,試翻轉這個序列使得i=1nSii\sum_{i=1}^n|S_i-i|最小

思路

暴力模擬是不行的

換一個角度想,旋轉佇列其實就是更改下標,我們考慮每次更改下標帶來的影響即可

程式碼

#include<cstdio>
#include<algorithm>
using namespace std;typedef long long ll;
ll n,a[4000005],ans,leq,geq,bz[4000005],now;
inline ll read()
{
	char c;int f=0,d=1;
	while
(c=getchar(),c<48||c>57)if(c=='-')d=-1;f=(f<<3)+(f<<1)+c-48; while(c=getchar(),c>47&&c<58) f=(f<<3)+(f<<1)+c-48; return d*f; } inline void write(ll x){if(x>9)write(x/10);putchar(x%10+48);return;} signed main() { n=read(); for(register int i=1;i<=n;i++
) { a[i]=read();ans+=abs(a[i]-i); if(a[i]>i) geq++,bz[min(n-i+a[i],a[i]-i)]++; else leq++; } now=ans; for(register int i=1;i<=n;i++) { now+=leq-geq;//不大於i的全部的值變大,大於i的全部的值變小 now+=a[n-i+1]-(n+1);//最後一個變成第一個,要進行特殊處理,以下同上 now+=a[n-i+1]-1; leq--;//此時不大於的少一個 if(a[n-i+1]>1) geq++
,bz[i+a[n-i+1]-1]++;//對第一個進行特判 else leq++; geq-=bz[i];leq+=bz[i];//處理1~n之間的 ans=min(ans,now);//儲存最優解 } write(ans); }