Mister B and PR Shifts,题解

题目链接

分析:

  题意很明白,不再多说了,直接分析题目,首先想一想暴力,直接枚举起点,然后求出来,时间复杂度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);
}
原文地址:https://www.cnblogs.com/wish-all-ac/p/12852494.html