• 【XSY2985】【BZOJ1367】【Baltic2004】sequence



    考虑两种情况:

    1.(a_1)<(a_2)<(a_3)<(a_4)...<(a_n)

    直接令(b_i)=(a_i),最小。

    2.(a_1)>(a_2)>(a_3)>(a_4)...>(a_n)

    初一的一道绝对值题是这题的弱化版。

    给定(a_1),(a_2)...(a_n),求一点x,使得(abs(a_1-x))+(abs(a_2-x))...+(abs(a_n-x))值最小

    直接求中位数即可(初一的知识——绝对值)

    同理,关于2.我们令(b_i)取1到i中位数即可。

    那么这道题我们就可以看做是许多个严格递减的序列,每一个序列的答案我们是可以知道的。所以我们所要做的就是合并答案即可。

    怎么维护每一次合并呢?

    我们想到了左偏树。

    对于左偏树,我们每放入一个新节点,我们就(-=i),使得原应严格下降的序列变成(a_{i-1}>=a_i),再判断新加入的节点是否符合这个规则,不符合就与上一个merge。

    因为我们是要求中位数,所以节点的size不应超过它的范围的二分之一再(+1),所以我们要一直(size--),同时删除这个节点。

    最后我们求答案即可。

    注:因为我们一开始就减去了i,所以在如果要输出序列是要加上i。

    #include<bits/stdc++.h>
    using namespace std;
    struct data
    {
    	int l,r,size,fa,val;
    }s[1000001];
    int val[1000001],n,k,cnt,ch[1000001][2],dis[1000001];
    long long ans;
    int merge(int x,int y)
    {
    	if(!x||!y)
    	{
    		return x+y;
    	}
    	if(val[x]<val[y])
    	{
    		swap(x,y);
    	}
    	ch[x][1]=merge(ch[x][1],y);
    	if(dis[ch[x][0]]<dis[ch[x][1]])
    	{
    		swap(ch[x][0],ch[x][1]);
    	}
    	dis[x]=dis[ch[x][1]]+1;
    	return x;
    }
    int read()
    {
    	char ch=getchar();
    	int sum=0,f=1;
    	while(ch<'0'||ch>'9')
    	{
    		if(ch=='-')
    		{
    			f=-1;
    		}
    		ch=getchar();
    	}
    	while(ch<='9'&&ch>='0')
    	{
    		sum=sum*10+ch-'0';
    		ch=getchar();
    	}
    	return sum*f;
    }
    int main()
    {
    	n=read();
    	dis[0]=-1;
    	for(int i=1;i<=n;i++)
    	{
    		val[i]=read();
    		val[i]-=i;
    	}
    	for(int i=1;i<=n;i++)
    	{
    		s[++cnt]=(data){
    			i,i,1,i,val[i] 
    		};
    		while(cnt!=1&&s[cnt-1].val>s[cnt].val)
    		{
    			cnt--;
    			s[cnt].fa=merge(s[cnt].fa,s[cnt+1].fa);
    			s[cnt].size+=s[cnt+1].size;
    			s[cnt].r=s[cnt+1].r;
    			while(s[cnt].size>(s[cnt].r-s[cnt].l+3)/2)
    			{
    				s[cnt].size--;
    				s[cnt].fa=merge(ch[s[cnt].fa][0],ch[s[cnt].fa][1]);
    			}
    			s[cnt].val=val[s[cnt].fa];
    		} 
    	}
    	int m=1;
    	for(int i=1;i<=n;i++)
    	{
    		if(i>s[m].r)
    		{
    			m++;
    		}
    		ans+=abs(s[m].val-val[i]);
    	}
    	printf("%lld
    ",ans);
    	m=1;
    	for(int i=1;i<=n;i++)
    	{
    		if(i>s[m].r)
    		{
    			m++;
    		}
    		printf("%d ",s[m].val+i);
    	}
    	return 0;
    } 
    
  • 相关阅读:
    微信公众号支付,iframe跨域
    QQ小程序
    米大师支付
    window下安装phalcon
    laravel 控制器多个方法共用一个路由
    Elasticsearch查询语法
    【机器学习基础】相似度计算之杰卡德相似度
    【机器学习基础】相似度计算之Dice系数
    【leetcode_medium】54. Spiral Matrix
    【leetcode_easy】1189. Maximum Number of Balloons
  • 原文地址:https://www.cnblogs.com/2017gdgzoi44/p/11379621.html
Copyright © 2020-2023  润新知