• 【洛谷P4331】Sequence 数字序列


    题目

    题目链接:https://www.luogu.com.cn/problem/P4331
    给定一个整数序列(a_1, a_2, ··· , a_n),求出一个递增序列(b_1 < b_2 < ··· < b_n),使得序列(a_i)(b_i)的各项之差的绝对值之和(|a_1 - b_1| + |a_2 - b_2| + ··· + |a_n - b_n|)最小。

    思路

    可以先将位置 (i) 上的数 (a[i]) 减去 (i),这样问题转化为求一个不降序列 (b)
    答案必然是将整个序列划分为若干块,使得每一块均取其中位数,那么需要满足每一块的中位数单调不降。
    可以用堆来维护每一块的中位数,假设前 (i-1) 个数字处理好了,加入第 (i) 个数字,那么就先把这个数字单独看成一块,然后不断判断如果最后一块的中位数小于前面一块的中位数,那么就将这两块的堆合并。然后需要不断弹出元素直到堆中元素数量不超过区间长度的一半。
    合并堆十分简单,直接用左偏树做就可以了。而因为我们会合并当且仅当后面一块的中位数小于前面一块,所以合并之后前面一块的中位数显然会变小,所以我们直接维护大根堆即可。
    最后输出方案的时候记得要加上 (i)
    时间复杂度 (O(nlog n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    
    const int N=1000010;
    int n,top,lc[N],rc[N],val[N],dis[N];
    ll ans;
    
    struct node
    {
    	int rt,l,r,size;
    }st[N];
    
    int read()
    {
    	int d=0; char ch=getchar();
    	while (!isdigit(ch)) ch=getchar();
    	while (isdigit(ch)) d=(d<<3)+(d<<1)+ch-48,ch=getchar();
    	return d;
    }
    	
    int merge(int x,int y)
    {
    	if (!x || !y) return x+y;
    	if (val[x]<val[y]) swap(x,y);
    	rc[x]=merge(rc[x],y);
    	if (dis[lc[x]]<dis[rc[x]]) swap(lc[x],rc[x]);
    	dis[x]=dis[rc[x]]+1;
    	return x;
    }
    
    int main()
    {
    	n=read();
    	dis[0]=-1;
    	for (int i=1;i<=n;i++)
    	{
    		val[i]=read()-i;
    		st[++top]=(node){i,i,i,1};
    		while (top>1 && val[st[top].rt]<val[st[top-1].rt])
    		{
    			st[top-1].r=st[top].r; st[top-1].size+=st[top].size;
    			st[top-1].rt=merge(st[top-1].rt,st[top].rt);
    			top--;
    			while (st[top].size>(st[top].r-st[top].l+1)/2+1)
    			{
    				st[top].rt=merge(lc[st[top].rt],rc[st[top].rt]);
    				st[top].size--;
    			}
    		}
    	}
    	for (int i=1;i<=top;i++)
    		for (int j=st[i].l;j<=st[i].r;j++)
    			ans+=abs(val[st[i].rt]-val[j]);
    	printf("%lld
    ",ans);
    	for (int i=1;i<=top;i++)
    		for (int j=st[i].l;j<=st[i].r;j++)
    			printf("%d ",val[st[i].rt]+j);
    	return 0;
    }
    
  • 相关阅读:
    JQ trigger函数无法触发a标签的两种解决方法
    Normalize.css
    wow.js中各种特效对应的类名
    利用伪元素:after清除浮动
    单词超出隐藏显示省略号(单行或多行)并设置是否将单词打断
    利用伪元素和css3实现鼠标移入下划线向两边展开效果
    css3 兼容各个浏览器
    html 初始化
    将博客搬至CSDN
    Linux配置问题
  • 原文地址:https://www.cnblogs.com/stoorz/p/14076468.html
Copyright © 2020-2023  润新知