zoukankan      html  css  js  c++  java
  • Codeforces 873E Awards For Contestants ST表

    原文链接https://www.cnblogs.com/zhouzhendong/p/9255885.html

    题目传送门 - CF873E

    题意

      现在要给 $n(nleq 3000)$ 个学生颁奖。

      记 $a_i$ 为第 $i$ 个学生在本次比赛中做出的题目数量。

      记 $b_i$ 为第 $i$ 个学生所获的奖项,其中 $1,2,3$ 分别表示他获得一、二、三等奖, $-1$ 表示不获奖,当然,一等奖最好,没奖最差。

      记 $cnt_i$ 为满足 $b_k=i$ 的 $k$ 的个数。

      一个合法的颁奖方案必须满足以下条件:

        对于任何的 $i,x,yin {1,2,3}$,

          1.  $cnt_i>0$

          2.  $cnt_xleq 2cnt_y$

        如果第 $i$ 个人比第 $j$ 个人做题数多,则第 $i$ 个人获得的奖不比第 $j$ 个人差。

      现在,记 $b_i=j$ 的 $i$ 中,使得 $a_i$ 最大的记为 $c_j$ , 使得 $a_i$ 最小的记为 $d_j$。

      请你在所有合法方案中选择 $d_1-c_2$ 最大的;如果有多个,再在其中选择 $d_2-c_3$ 最大的;如果有多个,再在其中选择 $d_3-c_{-1}$ 最大的;如果还有多个,那么选择任意方案。

      按照输入的人的顺序输出你选择的方案中各个人的奖项。

    题解

      VP 的时候想了个很真的假算法,好久以后才发现的。

      正确的做法:

      首先将所有人按照 $a$ 降序排列。

      枚举 $d_1$ 的位置 $i$ 

        枚举 $d_2$ 的位置 $i+j$

          在满足 $ileq 2j,jleq 2i$ 的情况下,继续下面的操作:

          令 $d3=i+j+k$ ,则 $k$ 需要满足:对于任何的 $i,x,yin {1,2,3}$,1.$cnt_i>0$ 2.$cnt_xleq 2cnt_y$。

          那么,$k$ 的取值范围是 $left[max(leftlfloorcfrac{i+1}2 ight floor,leftlfloorcfrac{j+1}2 ight floor,min(2i,2j,n) ight]$ ,于是我们需要找到一个 $k$ 满足 $a_k-a_{k+1}$ 最大。

          由于没有修改,我们可以用 ST表 预处理,$O(1)$ 实现询问。于是我们就可以得到要选择的 $k$ 了。每次通过新的 $i,j,k$ 生成新的 $d_1,d_2,d_3$ 与目前最优解择优录用。

      最终根据最优解定奖,别忘了最后要排序一遍把所有的人排回输入顺序。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=3005;
    int n,ST[N][14];
    struct pb{
    	int a,id,res;
    }a[N];
    bool cmpa(pb a,pb b){
    	return a.a>b.a;
    }
    bool cmpid(pb a,pb b){
    	return a.id<b.id;
    }
    int calc(int i){
    	return a[i].a-a[i+1].a;
    }
    int Query(int L,int R){
    	if (L>R)
    		return -1;
    	int d=log(R-L+1)/log(2.0);
    	int a=ST[L+(1<<d)-1][d],b=ST[R][d];
    	return calc(a)>calc(b)?a:b;
    }
    int main(){
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d",&a[i]),a[i].id=i;
    	sort(a+1,a+n+1,cmpa);
    	a[n+1].a=0;
    	for (int i=1;i<=n;i++){
    		ST[i][0]=i;
    		for (int j=1;j<=12;j++){
    			ST[i][j]=ST[i][j-1];
    			if (i-(1<<(j-1))>0&&calc(ST[i-(1<<(j-1))][j-1])>calc(ST[i][j]))
    				ST[i][j]=ST[i-(1<<(j-1))][j-1];
    		}
    	}
    	int d1=-1,d2=-1,d3=-1;
    	for (int i=1;i<=n;i++)
    		for (int j=1;i+j<=n;j++){
    			if (i>2*j||j>2*i)
    				continue;
    			int dd1=i,dd2=i+j,dd3=Query(dd2+max((i+1)/2,(j+1)/2),min(dd2+min(i*2,j*2),n));
    			int k=dd3-dd2;
    			if (dd3==-1||k<1)
    				continue;
    			if (d1==-1||calc(dd1)>calc(d1)||(calc(dd1)==calc(d1)&&(calc(dd2)>calc(d2)||(calc(dd2)==calc(d2)&&calc(dd3)>calc(d3)))))
    				d1=dd1,d2=dd2,d3=dd3;
    		}
    	for (int i=1;i<=d1;i++)
    		a[i].res=1;
    	for (int i=d1+1;i<=d2;i++)
    		a[i].res=2;
    	for (int i=d2+1;i<=d3;i++)
    		a[i].res=3;
    	for (int i=d3+1;i<=n;i++)
    		a[i].res=-1;
    	sort(a+1,a+n+1,cmpid);
    	for (int i=1;i<=n;i++)
    		printf("%d ",a[i].res);
    	return 0;
    }
    

      

  • 相关阅读:
    解决在linux环境安装setuptools的相关错误
    sql根据最小值去重
    linux重新安装python
    python 进阶(转自http://python.jobbole.com/82633/)
    redis做消息列队
    下载安装windows版Redis
    vue-cli 结构
    vue-cli 安装
    [python]爬虫学习(三)糗事百科
    jquery基础
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/9255885.html
Copyright © 2011-2022 走看看