2018年10月18日提高組 T2 健美貓
阿新 • • 發佈:2018-12-16
大意
給定一個長度為的序列,試翻轉這個序列使得最小
思路
暴力模擬是不行的
換一個角度想,旋轉佇列其實就是更改下標,我們考慮每次更改下標帶來的影響即可
程式碼
#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);
}