题目链接
分析:
题意很明白,不再多说了,直接分析题目,首先想一想暴力,直接枚举起点,然后求出来,时间复杂度n*n,显然不太好,所以我们考虑换一种方法枚举,当然本质还是枚举,其实你会发现变化i次和i+1次是由很强的关联性的,除了末尾的元素之外,i+1每个元素提供的值都会和i的相差1,而末尾元素之接特判一下就好了,我们只需要知道的是没次有多少个将会-1的(自然+1的也可以之接求得),我们来想一下这个问题,如果不考虑后面的元素回到前面,那么其实每个元素在什么时候由加变减是确定的,可以直接找到,而对于从后面新加入的元素,开始当然可以加上,然后记录一下从哪里开始把它减掉就好了,当然如果是1的话加上就会立刻减掉,也没有问题,最后再处理答案就好了。
当然,数组开2e6防止溢出。
代码:
#include <cstdio> const int maxn=2e6+10; int a[maxn]; int cj[maxn]; int kj[maxn]; long long ans[maxn]; long long Abs(int a){ long long s=(long long)a; return s>0?s:-s; } int main(){ int n; scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); if(a[i]-i>=0) cj[a[i]-i]++; } int s=0; long long mi=1e18; for(int i=1;i<=n;i++){ ans[0]+=Abs(a[i]-i); kj[0]+=cj[i-1]; } for(int i=1;i<=n-1;i++){ kj[i]+=kj[i-1]-cj[i-1]; cj[a[n-i+1]-1+i]++; kj[i+1]++; } for(int i=1;i<=n-1;i++){ ans[i]=ans[i-1]-Abs(a[n-i+1]-n)+Abs(a[n-i+1]-1); ans[i]-=(long long)kj[i]; ans[i]+=(long long)n-(long long)1-(long long)kj[i]; } for(int i=0;i<=n-1;i++) if(ans[i]<mi){ mi=ans[i]; s=i; } printf("%lld %d",mi,s); }