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;
    }
    

      

  • 相关阅读:
    poj 1579(动态规划初探之记忆化搜索)
    hdu 1133(卡特兰数变形)
    CodeForces 625A Guest From the Past
    CodeForces 625D Finals in arithmetic
    CDOJ 1268 Open the lightings
    HDU 4008 Parent and son
    HDU 4044 GeoDefense
    HDU 4169 UVALive 5741 Wealthy Family
    HDU 3452 Bonsai
    HDU 3586 Information Disturbing
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/CF873E.html
Copyright © 2011-2022 走看看