正题
题目大意
给出序列s(s∈[1,n])(s\in [1,n])(s∈[1,n]),将序列旋转
旋转操作
si=si+1(i∈[1,n−1])sn=s1\begin{matrix} \\s_i=s_{i+1}(i\in [1,n-1]) \\ s_n=s_1 \end{matrix}si=si+1(i∈[1,n−1])sn=s1
然后要求
∑i=1nsi−i\sum _{i=1}^ns_i-ii=1∑nsi−i
最小
解题思路
根据对答案的贡献,我们排除尾部过去,我们可以大致分为两种情况:
si<=i:fi=fi−1+1s_i<=i:f_i=f_{i-1}+1si<=i:fi=fi−1+1
si>i:fi=fi−1−1s_i>i:f_i=f_{i-1}-1si>i:fi=fi−1−1
然后我们用桶aia_iai记录在第i次旋转会两种形态互换的个数然后用addaddadd记录目前可以累加的,然后每次根据上面那个aia_iai来改变addaddadd。
至于最后一个,我们考虑一下s?−ns_?-ns?−n肯定是在第1种情况,然后要先用这个改变,然后在考虑
abs(s?−n)(s<=n)⇒n−s?abs(s_?-n)\ (s<=n) \Rightarrow n-s_?abs(s?−n) (s<=n)⇒n−s?
和
abs(s?−1)(s>=1)⇒s?−1abs(s_?-1)\ (s>=1) \Rightarrow s_?-1abs(s?−1) (s>=1)⇒s?−1
所以改变之后产生代价
(n−s?)+(s?−1)=2∗s?−n−1(n-s_?)+(s_?-1)=2*s_?-n-1(n−s?)+(s?−1)=2∗s?−n−1
code
#include<cstdio>
#include<algorithm>
#define N 2000010
using namespace std;
int n,s[N],a[N];
long long ans,sum,add;
int read(){int x=0,flag=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')flag=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*flag;
}
int check(int x,int y)
{if(x<=y) return y-x;else return n+y-x;
}
int main()
{scanf("%d",&n);for(int i=1;i<=n;i++){s[i]=read();a[check(i,s[i])]++;if(s[i]<=i) add++;sum+=abs(s[i]-i);}ans=sum;for(int i=1;i<n;i++){add--;sum+=abs(s[n-i+1]-1)-abs(s[n-i+1]-n);sum+=add*2-n+1;add+=a[i];ans=min(ans,sum);}printf("%lld",ans);
}