UPCOJ-5531 [COCI 2017-2018-1] - Hokej


Hokej(1s64M)

(hokei.cpp/c/pas)

【题目描述】

一场大型马拉松冰球锦标赛即将举行。就像在马拉松冰球比赛中经常出现的情况一样,比赛时长为M分钟。在球场上(),就像普通的冰球一样,每一个时刻,每个队有6名队员。然而,一场马拉松冰球比赛可以持续很长一段时间,所以教练们带了一群球员在公共汽车和飞机上,这样他们就可以在球员疲惫的时候进行替换。

其中一位教练是我们故事的英雄,他的名字叫Ante。在比赛中,AnteN个球员带到了赛场。对于每个球员,他知道两件事:球员质量K和球员耐力I。球员的耐力是球员在比赛中可以比赛的总时间。如果球员打了X分钟,然后在板凳上休息,然后再打Y分钟,他的总上场时间是X + Y。当一个球员的总分钟数等于他们的耐力时,他会感到疲倦,不能继续比赛,所以在那一刻,需要有人来代替他,否则他会在冰上昏倒,最后在医院(马拉松冰球是一种危险的游戏)

在一分钟的比赛中,球队的质量是球队球员的质量的总和。他不是一个伟大的教练,所以他要求你拿出最初的6名球员和替补上场时间,这样他就能在比赛的所有分钟内达到球队质量的最大可能的总和Z。有保证的是,在每分钟有六名球员参加比赛是有可能的。

例如,如果游戏持续3分钟,如果在第1分钟,团队的quailty15,在第二个12中,在第三个14中,Z将等于15 +12+14=41

请注意:在马拉松冰球比赛中,没有守门员,因为这样比赛很才会更有趣!

【输入格式】

输入的第一行包含正整数MN,游戏的时间在M分钟内,参加的队员数量N

以下N行每行包含两个正整数,KI,表示球员的质量和耐力。

玩家的编号从1N,按照输入的顺序(第一个队员的B编号是1,第二个是2,以此类推)

【输出格式】

输出的第一行必须包含来自任务的最大可能Z

第二行输出必须包含6个数字——即开始游戏的6个队员的编号。

第三行输出必须包含取代B的数量,不能超过3 *N

必须包含以下B行,为了从最早的最新替补队员, 替补队员的信息,每代三个数,X(1X < M)AB,其中X是替补队员加入游戏的时刻,A是退出比赛,并进入板凳席的球员编号,B是将加入比赛的球员的编号。允许在同一分钟内进行多次替换,但玩家不能进入游戏,然后在同一时间退出,反之亦然。

如果存在多个解决方案,则输出任何。

【输入样例1

200​ ​6

3​ ​200

4​ ​200

5​ ​200

6​ ​200

7​ ​200

8​ ​200

 

【输出样例1

6600

1​ ​2​ ​3​ ​4​ ​5​ ​6

0

【样例解释】

第一个测试案例的说明:不需要替补队员,所有队员从头到尾都在比赛。

【数据范围】

对于100%的数据:1IM500,0006N500,0001K100000;


题目大意:

有一个6人队伍需要比赛M分钟,一共有N个人,每个人有耐力和贡献,每次可以换人,要求总贡献最大。


分析:

最后答案要最大,可以贪心。我们把人按照贡献从大到小排序现在我们就要优先把他们填入一个柱子没填完

下一根接着填六个人我们可以看成六个柱子,我们一个一个地把他们填满


一个人可以在两个柱子中出现

              


因为一个人的最大耐力不超过M,所以不会重复(其实大于M也不影响)
每次开始填一个柱子时,记录first就是开始的人
如果有一个可以耐力为M,那么可以直接填满一个柱子


 附上代码:

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+12;
int M,n;

struct node
{
    int val,tim,id;
    bool operator < (const node & other ) const 
    {
        return val > other.val;
    }
}edge[N];

long long ans;

int first[N];

int x[N],a[N],b[N],id[N],tot;

bool cmp(int a,int b) {return x[a]<x[b];}
int main()
{
    freopen("hokej.in","r",stdin);
    freopen("hokej.out","w",stdout);
    scanf("%d%d",&M,&n);
    
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&edge[i].val,&edge[i].tim);
        edge[i].id=i;
    }
    
    sort(edge+1,edge+n+1);
    
    int remind=M,num=5,last=-1;
    for(int i=1;i<=n;i++)
    {
        if(num&&edge[i].tim==M&&remind!=M)
        {
            first[--num]=edge[i].id;
            ans+=1LL*M*edge[i].val;
            continue;
        }
        int Min=min(remind,edge[i].tim);
        
        ans+=1LL*Min*edge[i].val;
        
        if(remind==M) first[num]=edge[i].id;
        else {x[++tot]=M-remind;a[tot]=last;b[tot]=edge[i].id;}
        
        remind-=Min;edge[i].tim-=Min;
        if(!remind) num--,remind=M;
        if(num<0) break;
        if(edge[i].tim) i--;
        else last=edge[i].id;
    }
    printf("%lld\n",ans);
    for(int i=0;i<5;i++) printf("%d ",first[i]);printf("%d\n",first[5]);

    for(int i=1;i<=tot;i++) id[i]=i;
    sort(id+1,id+tot+1,cmp);
    printf("%d\n",tot);
    for(int i=1;i<=tot;i++) printf("%d %d %d\n",x[id[i]],a[id[i]],b[id[i]]);

    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/Heey/p/8987399.html