• 洛谷 2 月月赛 I & WdOI R1.5 / RdOI R3.5 Mystery


    好高妙啊!

    肯定是把 \(a_i - i * k\) ,这样就消除了 \(k\) 的限制,只有单调的限制。

    先讲讲我的垃圾做法。

    考虑递推求解。我们把每一段相等的视作一组,然后显然呈阶梯状。

    如果加入一个元素,他比最后一级阶梯高,我们就将它另开一级阶梯更优。

    否则,将它与阶梯平齐一定能得到对于当前不劣的解(因为我们如果下降上一级台阶一次会带来-1的贡献,同时这一位会有1的贡献,答案不变),我们想要它对将来依然优秀,即让这级台阶尽可能低,显然就是下降到较小中位数的位置,但可能不满足阶梯性质,于是可以合并两级阶梯。发现合并之后往下移答案会变劣(r-1 级下移 -1 贡献,r 级下移 0 贡献),所以每次合并最多合并一次。

    对顶堆维护每段中位数实现,启发式合并可以做到小常数 \(O(n \log^2 n)\) ,可过。

    主席树应该可以单 \(O(n\log n)\)

    然后就是发现了一个高妙做法。

    其与我本质不同在于答案计算。

    考虑我做法的合并部分,合并的数一大一小配对,除去新加的数都有:大的比上级台阶大,小的比上级台阶小,那直接把答案加上大小之差相当于就加进去了(也可视作没加进去,视作加进去了中位数也没变)。

    最后可能会剩下一个数,比阶梯小。加进阶梯对答案的贡献就是那个阶梯的最小中位数与该数的距离,因为加进去后它还是中位数。

    于是我们需要一个数据结构去维护中位数。发现我们的操作相当于对一个集合不断加入比中位数小的数。那么每个数只有两次机会作为最小中位数去计算答案(一次在中靠下,一次在中间)。那么我们把每个元素加进大根堆两次,根头就是我们当前最高阶梯的中位数,算一次答案就可以 pop 掉。

    相当巧妙,不论是实现上还是想法上。比 1A 高明到不知哪里去了。

    代码注释掉的是我的初做法:

    /*
    好高妙啊 
    */
    #include <map>
    #include <set>
    #include <queue>
    #include <cmath>
    #include <bitset>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    #define pii pair <int , int>
    #define mp make_pair
    #define fs first
    #define sc second
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    
    //const int Mxdt=100000; 
    //static char buf[Mxdt],*p1=buf,*p2=buf;
    //#define getchar() p1==p2&&(p2=(p1=buf)+fread(buf,1,Mxdt,stdin),p1==p2)?EOF:*p1++;
    
    template <typename T>
    void read(T &x) {
    	T f=1;x=0;char s=getchar();
    	while(s<'0'||s>'9') {if(s=='-') f=-1;s=getchar();}
    	while(s>='0'&&s<='9') {x=(x<<3)+(x<<1)+(s-'0');s=getchar();}
    	x *= f;
    }
    
    template <typename T>
    void write(T x , char s='\n') {
    	if(!x) {putchar('0');putchar(s);return;}
    	if(x<0) {putchar('-');x=-x;}
    	T tmp[25]={},t=0;
    	while(x) tmp[t++]=x%10,x/=10;
    	while(t-->0) putchar(tmp[t]+'0');
    	putchar(s); 
    }
    
    const int MAXN = 1e6 + 5;
    
    LL n , k;
    LL a[MAXN];
    
    //struct Op_Heap {
    //	priority_queue <LL , vector <LL> , greater <LL> > up;//up.size()==dw.size()||up.size()==dw.size()-1
    //	priority_queue <LL , vector <LL> , less <LL> > dw;
    //	LL Sum_up , Sum_dw;
    //	void Ins(LL x) {
    //		if(up.empty() || x <= up.top()) dw.push(x) , Sum_dw += x;
    //		else up.push(x) , Sum_up += x;
    //		
    //		while(up.size() + 1 < dw.size()) up.push(dw.top()) , Sum_up += dw.top() , Sum_dw -= dw.top() , dw.pop();//up >= dw - 1
    //		while(up.size() > dw.size()) dw.push(up.top()) , Sum_dw += up.top() , Sum_up -= up.top() , up.pop();//up <= dw
    //		//dw >= up >= dw - 1
    //	}
    //	LL calc() {return Sum_up - dw.top() * up.size() + dw.top() * dw.size() - Sum_dw;} 
    //	void merge(Op_Heap &H) {
    //		if(up.size() + dw.size() < H.up.size() + H.dw.size()) {
    //			swap(up , H.up);swap(Sum_up , H.Sum_up);
    //			swap(dw , H.dw);swap(Sum_dw , H.Sum_dw);
    //		}
    //		while(H.dw.size()) Ins(H.dw.top()) , H.dw.pop();
    //		while(H.up.size()) Ins(H.up.top()) , H.up.pop();
    //		H.Sum_dw = H.Sum_up = 0;
    //	}
    //}Q[MAXN];
    
    LL val[MAXN];
    int tp , T;
    
    int main() {
    	read(n),read(k);
    	for (int i = 1; i <= n; ++i) read(a[i]) , a[i] -= (i - 1) * k;
    	read(T);
    	
    //	tp = 1;val[1] = a[1];Q[1].Ins(a[1]);
    //	LL cur = 0;
    //	if(!T) write(cur);
    //	for (int i = 2; i <= n; ++i) {
    //		if(a[i] > val[tp]) tp ++ , val[tp] = a[i] , Q[tp].Ins(a[i]);
    //		else {
    //			cur -= Q[tp].calc();
    //			Q[tp].Ins(a[i]);
    //			cur += Q[tp].calc();
    //			if(tp > 1 && Q[tp].dw.top() <= val[tp - 1]) cur -= Q[tp].calc() , cur -= Q[tp - 1].calc() , Q[tp - 1].merge(Q[tp]) , tp -- , cur += Q[tp].calc();
    //			val[tp] = Q[tp].dw.top();
    //		}
    //		if(!T || i == n) write(cur);
    //	}
    	
    	priority_queue <LL , vector <LL> , less <LL> > q;
    	LL ans = 0;
    	for (int i = 1; i <= n; ++i) {
    		q.push(a[i]),q.push(a[i]);
    		ans += q.top() - a[i];q.pop();
    		if(!T || i == n) write(ans);
    	}
    	
    	return 0;
    }
    
  • 相关阅读:
    Windows下 maven3.0.4的安装步骤+maven配置本地仓库
    eclipse+webservice开发实例
    android:layout_gravity和android:gravity属性的差别
    再议指针---------函数回调(qsort函数原理)
    Windows下curl使用
    jquery.validate+jquery.form提交的三种方式
    java final keyword
    URAL 1577. E-mail(简单二维dp)
    【 D3.js 入门系列 --- 7 】 理解 update, enter, exit 的使用
    Code:log4
  • 原文地址:https://www.cnblogs.com/Reanap/p/15874356.html
Copyright © 2020-2023  润新知