zoukankan      html  css  js  c++  java
  • 【洛谷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;
    }
    
  • 相关阅读:
    POJ3783Balls[DP 最坏情况最优解]
    openjudge2989糖果[DP 01背包可行性]
    POJ1160 Post Office[序列DP]
    石子合并[DP-N3]
    POJ1065Wooden Sticks[DP LIS]
    POJ3636Nested Dolls[DP LIS]
    LCIS(最长公共上升子序列)Vijos1264神秘的咒语
    Vijos1680距离/openjudge2988计算字符串的距离[DP]
    Vijos1392拼拼图的小衫[背包DP|二维信息DP]
    NOIP2000方格取数[DP]
  • 原文地址:https://www.cnblogs.com/stoorz/p/14076468.html
Copyright © 2011-2022 走看看