洛谷 P4331 [BalticOI 2004]Sequence 数字序列

给定一个整数序列\(a_1,a_2...a_n(n\leq10^6)\),求出一个递增序列\(b_1<b_2<···<b_n\),使得序列\(a_i\)\(b_i\)的各项之差的绝对值之和\(|a_1 - b_1| + |a_2 - b_2| + ··· + |a_n - b_n|\)最小

这题挺有意思的

首先我们可以把\(a_i\)加上\(i\),那么我们求的\(b_i\)也加上\(i\),这样不但对结果没有影响,而且可以把b的单调递增限制转化为单调不降

然后我们考虑对a的一个单调不降的区间,那么答案肯定是\(b_i=a_i\)

而对于a的单调下降的区间,答案为\(b_i=a_{mid}\)\(a_mid\)为a的这段区间的中位数

很容易想到a肯定是由许多这样的两种区间构成的,那么对于两段a的单调下降区间,我们可以对其合并再求中位数

于是做法就出来了,我们开栈记录当前的最值\(w_{cnt}\),然后向后扫a,如果\(a_i<w_{cnt}\),那么就合并这两个点的中位数

中位数还是比较好求的,因为是中间大,所以用堆存个\(size\),如果比区间的一半还大就pop掉,这样最大值就是中位数了

这题还需要合并,所以开可并堆就好了

Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
const int N = 1e6;
using namespace std;
int n,lc[N + 5],rc[N + 5],rt[N + 5],size[N + 5],L[N + 5],R[N + 5],cnt,dist[N + 5];
long long ans,b[N + 5],a[N + 5],v[N + 5];
int merge(int x,int y)
{
    if (!x || !y)
        return x + y;
    if (v[y] > v[x])
        swap(x,y);
    rc[x] = merge(rc[x],y);
    if (dist[lc[x]] < dist[rc[x]])
        swap(lc[x],rc[x]);
    dist[x] = dist[rc[x]] + 1;
    return x;
}
long long myabs(long long x)
{
    return x > 0 ? x : -x;
}
int main()
{
    scanf("%d",&n);
    for (int i = 1;i <= n;i++)
        scanf("%lld",&v[i]),v[i] -= i;
    for (int i = 1;i <= n;i++)
    {
        a[++cnt] = v[i];
        L[cnt] = R[cnt] = rt[cnt] = i;
        size[cnt] = 1;
        while (cnt > 1 && a[cnt] < a[cnt - 1])
        {
            rt[cnt - 1] = merge(rt[cnt],rt[cnt - 1]);
            size[cnt - 1] += size[cnt];
            R[cnt - 1] = R[cnt];
            cnt--; 
            while (size[cnt] > (R[cnt] - L[cnt] + 1 + 2) / 2)   //上取整
            {
                size[cnt]--;
                rt[cnt] = merge(lc[rt[cnt]],rc[rt[cnt]]);
            }
            a[cnt] = v[rt[cnt]];
        }
    }
    for (int i = 1;i <= cnt;i++)
        for (int j = L[i];j <= R[i];j++)
            b[j] = a[i];
    for (int i = 1;i <= n;i++)
        ans += myabs(b[i] - v[i]);
    cout<<ans<<endl;
    for (int i = 1;i <= n;i++)
        printf("%lld ",b[i] + i);
    return 0;
}
posted @ 2020-06-15 10:06  eee_hoho  阅读(212)  评论(0编辑  收藏  举报