4007. 【GDKOI2015】星球杯

64 篇文章 0 订阅

Description

Input

第一行两个整数 N (2 <= N <= 200)和 K(1 <= K <= N/2),分别表示参赛人数和每轮预赛的晋级人数。
接下来 N 行, 第 i 行为第 i 个选手的情况, 每行三个整数, 分别为该选手参加第一轮预赛的得分 Xi,参加第二轮预赛的得分 Yi,以及该选手的所属国度 Zi( 1 表示阿斯嘉德, 0表示米德加尔特)。
注意: Xi 之间的值互不相同, Yi 之间的值互不相同。

Output

输出一行一个整数,为阿斯嘉德最高的得分总和。

Sample Input

5 2
90 60 0
40 50 1
3 1 1
4 4 0
1 2 1

Sample Output

54

Data Constraint

对于 30%数据, N≤20;
对于 100%数据, N≤200, Xi, Yi 的总和小于 2^31。

Solution

题目大意就是给你n个人的国籍(0/1)和两轮比赛的分数,他们必须参加两轮中的一轮比赛,将每轮比赛分数排名的前k个的加入到国家的总分,最大化1国的分数。

注意到N非常小,于是我们可以枚举一个分界线,表示第一轮比赛中排名第K的人的分数,设为Kx,那么大于等于Kx的加入总分

那么我们可以发现,对于所有0国的人i,若Xi<Kx,则显然把他丢进第一轮里。

还可以发现对于所有1国的人i,若Xi<Kx,则显然把他放进第二轮

那么我们将除去0国Xi<Kx的人抽出来组成一个新的集合,再来做dp。

按第二轮分数从大到小排序 我们可以设f[i][j]表示在前i个选手中,有j个选手参加了第一轮预选赛并且晋级时1王国的选手最高的得分总和。因为所有被选出来dp的人要么进入第一轮的前K位,要么进入了第二轮,又因为第二轮分数有序,所以i-j即为第二轮的前列,后面的人的排名不可能超过他们。

至此,有三种情况:

① 0队选手且分数≥x

           1、放第一场 F[i-1][j-1] (j>0)

           2、放第二场 F[i-1][j]

② 1队选手且分数< x

           1、放第二场 F[i-1][j]+Sec[i] (i>j & i-j<=k)          //第二轮晋级人数不能超过k,超过则不计分

           F[i-1][j] (else)

③ 1队选手且分数≥x

           1、放第一场 F[i-1][j-1]+Fir[i] (j>0)

           2、放第二场 F[i-1][j]+Sec[i] (i>j & i-j<=k)                            

           F[i-1][j] (else)

最后答案即为max{f[当前选出集合元素个数][0~k]}

 

Code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define mem(x,y) memset(x,y,sizeof(x))
#define I int
#define F(i,a,b) for(I i=a;i<=b;i++)
#define N 202
using namespace std;
I rd(){
	I x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x;
}
I n,k,tot,ans,f[N][N];
struct al{I x,y,z;}a[N];
struct ct{I x,y,z;}c[N];
I cmp(ct s,ct t){return s.y>t.y;}
int main(){
	n=rd();k=rd();
	F(i,1,n){
		a[i]=al{rd(),rd(),rd()};
	}
	F(l,1,n){
		tot=0;
		mem(f,0);
		F(i,1,n){
			if(a[i].x>=a[l].x){
				++tot;
				c[tot]=ct{a[i].x,a[i].y,a[i].z};
			}
			else{
				if(a[i].z==1){
					++tot;
					c[tot]=ct{a[i].x,a[i].y,a[i].z};
				}
			}
		}
		sort(c+1,c+1+tot,cmp);
		F(i,1,tot){
			F(j,0,min(i,k)){
				f[i][j]=max(f[i][j],f[i-1][j]);
				if(!c[i].z){
					if(j) f[i][j]=max(f[i][j],f[i-1][j-1]);
				}
				else{
					if(c[i].x<a[l].x){
						if(i>j&&i-j<=k) f[i][j]=max(f[i][j],f[i-1][j]+c[i].y);
					}
					else{
						if(j) f[i][j]=max(f[i][j],f[i-1][j-1]+c[i].x);
						if(i>j&&i-j<=k) f[i][j]=max(f[i][j],f[i-1][j]+c[i].y);
					}
				}
				ans=max(ans,f[i][j]);
			}
		}
	}
	printf("%d\n",ans);
	return 0;
}


作者:zsjzliziyang 
QQ:1634151125 
转载及修改请注明 
本文地址:https://blog.csdn.net/zsjzliziyang/article/details/98475050

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值