zoukankan      html  css  js  c++  java
  • BZOJ1112[POI2008]砖块Klo——非旋转treap

    题目描述

    N柱砖,希望有连续K柱的高度是一样的. 你可以选择以下两个动作 1:从某柱砖的顶端拿一块砖出来,丢掉不要了. 2:从仓库中拿出一块砖,放到另一柱.仓库无限大. 现在希望用最小次数的动作完成任务.

    输入

    第一行给出N,K. (1 ≤ k ≤ n ≤ 100000), 下面N行,每行代表这柱砖的高度.0 ≤ hi ≤ 1000000

    输出

    最小的动作次数

    样例输入

    5 3
    3
    9
    2
    3
    1

    样例输出

    2
     
    考虑对于只有$k$个数的序列的最优解,显然是将所有数都变成中位数(因为如果变成的数比中位数小或者大都会有多于一半的数要改变)。
    那么我们只需要维护出有$k$个连续数的序列,求出中位数并维护比中位数大的数的和及比中位数小的数的和即可得到这$k$个数的最优解,用平衡树维护即可。
    对于$n$个数的序列只需要每次对连续$k$个数维护信息并求最优解然后取最小值即可。每次将第$i$个数删除,再将第$i+k$个数插入。
    #include<set>
    #include<map>
    #include<queue>
    #include<stack>
    #include<cmath>
    #include<vector>
    #include<cstdio>
    #include<bitset>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ll long long
    using namespace std;
    ll ans;
    int n,k;
    int s[100010];
    struct treap
    {
    	treap *ls,*rs;
    	int size;
    	int val;
    	int rnd;
    	ll sum;
    	treap(){}
    	treap(treap *son,int v)
    	{
    		ls=rs=son;
    		size=1;
    		val=v;
    		sum=1ll*v;
    		rnd=rand();
    	}
    	void pushup()
    	{
    		sum=ls->sum+rs->sum+val;
    		size=ls->size+rs->size+1;
    	}
    }tr[100010],nil;
    typedef treap* node;
    node root,null,cnt;
    node a,b,c;
    inline void init()
    {
    	nil=treap(NULL,0);
    	null=&nil;
    	null->ls=null->rs=null;
    	null->size=0;
    	root=null;
    	cnt=tr;
    }
    inline node build(int v)
    {
    	*cnt=treap(null,v);
    	return cnt++;
    }
    inline node merge(node x,node y)
    {
    	if(x==null)
    	{
    		return y;
    	}
    	if(y==null)
    	{
    		return x;
    	}
    	if(x->rnd<y->rnd)
    	{
    		x->rs=merge(x->rs,y);
    		x->pushup();
    		return x;
    	}
    	else
    	{
    		y->ls=merge(x,y->ls);
    		y->pushup();
    		return y;
    	}
    }
    inline void split1(node rt,node &x,node &y,int k)
    {
    	if(rt==null)
    	{
    		x=y=null;
    		return ;
    	}
    	if(rt->ls->size>=k)
    	{
    		y=rt;
    		split1(rt->ls,x,y->ls,k);
    	}
    	else
    	{
    		x=rt;
    		split1(rt->rs,x->rs,y,k-1-rt->ls->size);
    	}
    	rt->pushup();
    }
    inline void split2(node rt,node &x,node &y,int k)
    {
    	if(rt==null)
    	{
    		x=y=null;
    		return ;
    	}
    	if(rt->val>=k)
    	{
    		y=rt;
    		split2(rt->ls,x,y->ls,k);
    	}
    	else
    	{
    		x=rt;
    		split2(rt->rs,x->rs,y,k);
    	}
    	rt->pushup();
    }
    inline void query()
    {
    	split1(root,a,b,k/2);
    	split1(b,b,c,1);
    	ll res=1ll*a->size*b->val-a->sum;
    	res+=c->sum-1ll*c->size*b->val;
    	ans=min(res,ans);
    	root=merge(merge(a,b),c);
    }
    int main()
    {
    	srand(12378);
    	scanf("%d%d",&n,&k);
    	ans=1ll<<60;
    	init();
    	for(int i=1;i<=n;i++)
    	{
    		scanf("%d",&s[i]);
    	}
    	for(int i=1;i<=k;i++)
    	{
    		split2(root,a,b,s[i]);
    		root=merge(merge(a,build(s[i])),b);
    	}
    	query();
    	for(int i=k+1;i<=n;i++)
    	{
    		split2(root,a,b,s[i-k]);
    		split1(b,b,c,1);
    		root=merge(a,c);
    		split2(root,a,b,s[i]);
    		root=merge(merge(a,build(s[i])),b);
    		query();
    	}
    	printf("%lld",ans);
    }
  • 相关阅读:
    记某app内购破解 – 安卓逆向菜鸟的初体验
    初探Android逆向:通过游戏APP破解引发的安全思考
    用IKVMC将jar转成dll供c#调用
    Java与.net 关于URL Encode 的区别
    RSA加密、解密、签名、验签的原理及方法
    C#使用SHA1加密类(RSAFromPkcs8)支持1024位和2048位私钥
    java与.net平台之间进行RSA加密验证
    RSA密钥,JAVA与.NET之间转换
    全面解决.Net与Java互通时的RSA加解密问题,使用PEM格式的密钥文件
    Android中Activity的启动模式(LaunchMode)和使用场景
  • 原文地址:https://www.cnblogs.com/Khada-Jhin/p/10731075.html
Copyright © 2011-2022 走看看