zoukankan      html  css  js  c++  java
  • uoj#280. 【UTR #2】题目难度提升(构造)

    传送门

    咱先膜一下(GXZ)再说

    我们先把序列从小到大排序,然后分情况讨论

    无解是不存在的,从小到大输出所有数肯定可行

    情况一,如果(a[mid]=a[mid+1]),因为最终的中位数也是它们,那么我们可以让中位数一直等于(a[mid]),找到最大的(k)满足(a[k]=a[mid]),那么就先删(k),然后再删(k-1,n,k-2,n-1,...)那么显然这个过程中中位数始终为(a[mid]),且满足字典序最大

    情况二,如果(a[mid] eq a[mid+1])且存在(k<lceilfrac n2 ceil,a_k=a_{k+1}),那么我们可以从(k)开始取,然后按(k-1,n,k-2,n-1,...)的顺序取,最后前面的数一定会被取完,而且这个过程中中位数不变

    情况三,第一个数只能取(a[1]),因为很明显删数的过程中要始终满足删的数不能小于已删的数的中位数否则(GG)

    于是维护一个叫做对顶堆的东西,简单来说就是把小的数放一个大根堆里,大的数放一个小根堆里,并保证两堆的元素个数之差不超过(1),那么中位数只要从两个堆顶取就行了

    对于剩下的所有未删除的数,因为按照我们上面的做法,情况一是已经做完了,情况二和情况三都会删到只剩一个连续的区间,且这个区间的中位数大于等于已经删的数的中位数,于是每一次加入能使中位数大于等于剩下的最小的数的就行了

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define IT set<int>::iterator
    #define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
    #define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
        R int res,f=1;R char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    char sr[1<<21],z[20];int C=-1,Z=0;
    inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
    void print(R int x){
        if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
        while(z[++Z]=x%10+48,x/=10);
        while(sr[++C]=z[Z],--Z);sr[++C]=' ';
    }
    const int N=1e5+5;
    multiset<int>s;priority_queue<int>A,B;
    int a[N],vis[N],n;
    void push(int x){
    	if(A.empty()||x<=A.top())A.push(x);
    	else B.push(-x);
    	if(A.size()<B.size())A.push(-B.top()),B.pop();
    	if(A.size()-B.size()>1)B.push(-A.top()),A.pop();
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	n=read();
    	fp(i,1,n)a[i]=read();
    	sort(a+1,a+1+n);
    	int mid=(n+1)>>1;
    	if(a[mid]==a[mid+1]){
    		while(mid<n&&a[mid]==a[mid+1])++mid;
    		print(a[mid]);
    		int p=mid-1,q=n;
    		while(p||q>mid){
    //			printf("%d %d
    ",p,q);
    			if(p)print(a[p--]);
    			if(q>mid)print(a[q--]);
    		}return Ot(),0;
    	}
    	while(mid>1&&a[mid]!=a[mid-1])--mid;
    	print(a[mid]),vis[mid]=1;
    	int p=mid-1,q=n;IT it;
    	while(p&&q>mid)print(a[p]),print(a[q]),vis[p--]=vis[q--]=1;
    	fp(i,1,n)if(vis[i])push(a[i]);else s.insert(a[i]);
    	while(!s.empty()){
    		p=*s.begin();
    		if(A.size()==B.size())it=(p>=-B.top())?--s.end():s.begin();
    		else{
    			if(!B.empty()&&p*2>=A.top()-B.top())it=--s.end();
    			else it=--s.upper_bound(p*2-A.top());
    		}
    		print(*it),push(*it),s.erase(it);
    	}
    	return Ot(),0;
    }
    
  • 相关阅读:
    Day5下午解题报告1
    Linux 命令整理
    [置顶] 正则表达式应用:匹配email地址
    IE浏览器下web调试工具之--IE WebDeveloper介绍
    ORACLE客户端乱码
    冒泡排序
    【C++】第二章:Hello World!
    hdu4710
    (SQL SERVER) (ORACLE) (ACCESS)(POSTGRE SQL)四种数据库操作C#代码
    How to calculate the undo_retention time
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10287667.html
Copyright © 2011-2022 走看看