7-2 最強チームの公平なる選び方 (20 分)

程序设计竞赛的参赛队伍通常由3人组成。G队长从PTA下载了计算机专业全体学生的刷题成绩,想从中选出三名学生组成一支最强队伍。成绩单只列出了每位学生的学号和成绩,按学号从小到大排列。显然,最简单的方法是直接找出成绩排名前三的学生,但选出的学生可能集中在个别班级里,对其他班级有失公平;较公平的方法是先从每个班选成绩最好的,再从中筛选三人,但必须知道分班的情况。队长思索了半响,突然想到虽然每个班级的学生人数有出入,但上限是固定的,并且同一个教学班的学生其学号是连续编号的,由此设计出一个即公平(每个班最多选1人)又便利(不用分班)的最强队伍选择方法。

输入格式:

输入两行数据,第一行给出两个正整数N和K,表示学生总人数和班级人数上限,满足2K<N≤105 (至少有三个班)。接下来一行给出N个正整数,用空格分开,依次表示从学号0到学号N-1的学生成绩。末尾的成绩后面没有空格。所有成绩值都在区间[1,105]以内。

输出格式:

输出两行数据。第一行给出选出的最强队伍的总成绩;第二行给出组队的三名学生的学号a  b  c,满足 b−a≥K∧c−b≥K。数值间用空格分开,末尾不留空格。 如果最强队伍有多组,输出学号序列字典序最小的队伍。

输入样例1:

10 3
6 2 7 8 9 2 8 5 7 1

输出样例1:

22
0 3 6

注:学号0+学号4+学号8也是最强队伍,但字典序较大。

输入样例2:

6 2
1 2 3 4 5 6

输出样例2:

12
1 3 5

代码长度限制

16 KB

时间限制

400 ms

内存限制

64 MB

代码

#include <iostream>
using namespace std;
#include <queue>
#include <vector>
void clear(int*a,int size)
{
    for(int i=0;i<size;i++)
    {
        a[i]=0;
    }
}
int main()
{
    //输入两行数据,第一行给出两个正整数N和K,表示学生总人数和班级人数上限,满足2K<N≤10^5(至少有三个班)。
    int N,K;//学生总人数N+班级人数上限K
    cin>>N>>K;
    int score[100000]={0};//储存全部同学的初始成绩
    //接下来一行给出N个正整数,用空格分开,依次表示从学号0到学号N-1的学生成绩。末尾的成绩后面没有空格。所有成绩值都在区间[1,10^5]以内。
    //输出两行数据。第一行给出选出的最强队伍的总成绩;第二行给出组队的三名学生的学号a  b  c,满足 b−a≥K∧c−b≥K。数值间用空格分开,末尾不留空格。
    //如果最强队伍有多组,输出学号序列字典序最小的队伍。
    //a的值在0到(N-1)-2*K之间
    //b的值在a+K到(N-1)-K之间
    //c的值在b+K到N-1之间
    int maxScore1[N];//到目前为止的第一个最大数
    int maxScore2[N];//到目前为止的第二个和第一个的最大数
    int maxScore3[N];//到目前为止的三个数的和的最大数
    int index1[N];//第一个最大数的最先位置
    int index2[N];//第二个和最大数的最先的位置
    int index3[N];//第三个三数之和最大值最先的位置
    //清零
    clear(maxScore1,N);
    clear(maxScore2,N);
    clear(maxScore3,N);
    clear(index1,N);
    clear(index2,N);
    clear(index3,N);
    cin>>score[0];
    //开始操作
    maxScore1[0]=score[0];
    index1[0]=0;
    for(int i=1;i<=N-1;i++)
    {
        cin>>score[i];//原值
        if(score[i]>maxScore1[i-1])
        {
            maxScore1[i]=score[i];
            index1[i]=i;
        }
        else
        {
            maxScore1[i]=maxScore1[i-1];
            index1[i]=index1[i-1];
        }
    }
    maxScore2[K]=score[K]+maxScore1[0];
    index2[K]=K;
    for(int i=K+1;i<=N-1;i++)
    {
        if(maxScore1[i-K]+score[i]>maxScore2[i-1])
        {
            maxScore2[i]=maxScore1[i-K]+score[i];
            index2[i]=i;
        }
        else
        {
            maxScore2[i]=maxScore2[i-1];
            index2[i]=index2[i-1];
        }
    }
    maxScore3[2*K]=score[2*K]+maxScore2[K];
    index3[2*K]=2*K;
    for(int i=2*K+1;i<=N-1;i++)
    {
        if(maxScore2[i-K]+score[i]>maxScore3[i-1])
        {
            maxScore3[i]=maxScore2[i-K]+score[i];
            index3[i]=i;
        }
        else
        {
            maxScore3[i]=maxScore3[i-1];
            index3[i]=index3[i-1];
        }
    }
    cout<<maxScore3[N-1]<<endl;
    int c=index3[N-1];
    int b=index2[c-K];
    int a=index1[b-K];
    cout<<a<<" "<<b<<" "<<c;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值