剩下40分钟了,感觉随便打个暴力,不然没提高了……
暴力能不能AC呢?数据随机生成,均摊复杂度能过关吧?能卡吗?构造极端数据试试?让相邻大小数字距离约等于$\sqrt{n}$,最大次数总和约为$n * \sqrt{n}$,交上去,果然AC了!

#include <bits/stdc++.h>
using namespace std;
int n, m, i, j, k, s, a[200005];
int main(){
    scanf("%d", &n);
    for(i=1; i<=n; i++){
        scanf("%d", &a[i]);
    }
    for(i=1; i<=n; i++){
        for(j=1, s=n+n; j<=s; j++){//暴力枚举左右两边
            if(i > j) s = min(s, abs(a[i]-a[i-j])+j);
            if(i+j <= n) s = min(s, abs(a[i]-a[i+j])+j);
        }//距离超过最优值break
        printf("%d ", s);//看样例感觉范围挺小的
    }
    return 0;
}

线段树做法:枚举每个元素a[i],有左右两边需要查找,做法类似;对于左边情况,有比a[i]大的,也有小的,分开处理就可以去掉绝对值。左边的是a[j],如果它小,那么就是a[i]-a[j]+i-j,其中a[i]+i不变,用线段树维护-a[j]-j的最小值即可。大的同理。

#include <bits/stdc++.h>
#define N 200005
using namespace std;
int n, m, i, j, k, c, p, q, a[N], v[N];
int d[N*4], lc[N*4], rc[N*4];
void gai(int &p, int l, int r, int k, int x){
    if(!p) p = ++c;
    if(l == r) d[p] = x;//该位置只修改1次
    else{
        int m=l+r>>1;
        if(k <= m) gai(lc[p], l, m, k, x);
        else gai(rc[p], m+1, r, k, x);
        d[p] = min(d[p], x);//维护区间最小值
    }
}
int cha(int p, int l, int r, int x, int y){
    if(!p || x<=l && r<=y) return d[p];
    int m=l+r>>1, s=1e9;
    if(x <= m) s = min(s, cha(lc[p], l, m, x, y));
    if(y > m) s = min(s, cha(rc[p], m+1, r, x, y));
    return s;//查询区间最大值
}
int main(){
    scanf("%d", &n);
    for(i=1; i<=n; i++){
        scanf("%d", &a[i]);
        v[i] = n + n;
    }
    memset(d, 9, sizeof(d));
    for(i=1; i<=n; i++){//处理左边
        v[i] = min(v[i], cha(p, 1, n, 1, a[i]-1)+i+a[i]);
        v[i] = min(v[i], cha(q, 1, n, a[i]+1, n)+i-a[i]);
        gai(p, 1, n, a[i], -a[i]-i);//a[i]大,前面的小
        gai(q, 1, n, a[i], a[i]-i);//a[i]小,前面的大
    }
    memset(d, 9, sizeof(d));
    memset(lc, c=0, sizeof(lc));
    memset(rc, p=q=0, sizeof(rc));
    for(i=n; i>=1; i--){//处理右边,两边取最小值
        v[i] = min(v[i], cha(p, 1, n, 1, a[i]-1)-i+a[i]);
        v[i] = min(v[i], cha(q, 1, n, a[i]+1, n)-i-a[i]);
        gai(p, 1, n, a[i], -a[i]+i);
        gai(q, 1, n, a[i], a[i]+i);
    }
    for(i=1; i<=n; i++) printf("%d ", v[i]);
    return 0;
}

作者 crxis

发表回复