【北理乐学】机智的大师

【题目】

题目背景

    在BIT的网络教室里,有一位叫做大师的传奇的人物。大师卖萌卖得好,黑人黑得好,写代码更是一绝。她在轻松AC了题目之后还要故意重新交几次默默刷高自己的罚分使自己排名靠后以深藏功与名,但是由于大师压倒性的实力,她还是并列了网教的第一。在一个叫什么什么M的神秘组织里,大师的代号是07。

    大师的RP值一向很高,然而,由于最近她联合了YW大神在网教里黑掉了无辜的渣渣,大师的RP值骤减(黑人是要掉RP的哦~)。期末考试临近,大师想以一个高RP状态去参加考试(其实吧即使大师的RP为0也能拿满分),于是大师决定周五上午到理教201在陈老师的C语言课上收集RP。

   那么大师是怎样获取RP的呢?她有一个独特的技能——「嘤嘤」。美丽的大师坐到你身旁,用她那水汪汪的眼睛望着你,然后———— ”>.<嘤嘤~” 使你不忍心不分给她一些RP。

    现在已知陈老师的课堂里有N位无辜的同学/老师(不排除鹰哥被嘤嘤的可能性= =),每个人有一个固定的RP值rp[i],大师会对Ta们使出嘤嘤技能。大师每对一个RP比自己低的人(例如李渣渣)使出嘤嘤,大师会获得1点RP值,每对一个RP值大于等于自己RP的人使出嘤嘤,大师会获得2点RP。(大师说:赚RP是多么不容易啊,大家捡到一卡通钱包什么的一定要还给失主会获得大量RP哒)。机智的大师当然会安排一个最佳的方案使得自己达到最高的RP。

大师收集完RP之后要去和渣渣玩儿猜拳。渣渣想知道大师最多能获得多少RP以估测自己获胜的几率。然而由于渣渣的IQ非常捉鸡,他找到了聪明的你,请你帮渣渣计算一下大师的RP能够达到的最大值。

PS:大师,YW大神和渣渣祝大家端午节快乐~

题目作者

 渣渣

输入

第一行:一个数字N (0

第二行:一个数字R (0<=R<=10000),代表大师的初始RP值。

第三行:N个正整数,代表每个人的RP值(0<=rp[i]<=10000)。

输出

    大师能够达到的最高的RP

输入样例

5

100

90 100 80 120 100

输出样例

107

 测试输入期待的输出时间限制内存限制额外进程

Input1:

5↵

100↵

90 100 80 120 100↵

Output1:

107↵

Input2:

10↵

12↵

1 9 6 19 11 16 10 6 15 16↵

Output2:

26↵

【题目分析】初读该题, 大概对此题有一个基本理解:首先一个人A有一个初始的RP值r,同时,他的身边有N个人, 他们各自也有相应的rp值,A遇到一个rp值大于等于自己的人,自己的RP便会+2(在后面我们会把这个操作成为吸2点RP),否则RP+1,显而易见,A的RP是非增的。题目的目的是使A拥有最大的RP值,这是一个典型的贪心问题(我们可以通过求出各个子问题的最优解得到整个问题的最优解,有的问题看似是贪心,但贪心没有办法得到最优的结果,例如01背包问题,还有大家熟知的将军饮马问题)。所以,我们想让A的RP值达到最大,我们只需让他的RP值尽量多的+2,故我们首先要去寻找RP值大于等于A的,从小到大依次吸(在这里我们为什么从小到大吸,其原因举个例子便显而易见。比如现在A的初始RP是100,旁边有几个人,他们的RP分别是100, 100, 102,假如你先吸102,那么这之后A的RP便是102, 剩下的两个100只能各自吸1,得到的最大RP值只能是102+1+1=104,而如果我们先吸一个RP为100的,再吸一个RP为102的,那么我们此时的RP可以达到100+2+2+1=105,容易证明这是最优解)。要注意的是,我们此时的从小到大吸指的是rp大于A初始RP的人从小到大排序。


【题目难点】

其实这是一道贪心+排序题(当然不学计算机专业的话也没必要知道这是贪心问题,只需了解这个问题就是将整个问题内所有自问题均寻求出它们的最优解即可),并没有什么难点。在这里写一写简单的伪代码。


【C语言代码】

#include

#define maxn 1005

int rp[maxn];

int main() {

    int n, r, sign=0;

    scanf("%d%d", &n, &r);

    for (int i = 0; i < n; i++)

        scanf("%d", &rp[i]);

    for(int i=0;i

        for(int j=0;j

            if(rp[j]

                int t=rp[j+1];

                rp[j+1]=rp[j];

                rp[j]=t;

            }

        }

    }

    for(int i=0;i

        if(rp[i]>=r&&rp[i+1]<=r)

            sign=i;

    }

    for(int i=sign;i>=0;i--){

        if(rp[i]>=r)    r+=2;

        else    r++;

    }

    r += n - sign - 1;

    printf("%d\n",r);

    return 0;

}


【Hint】

刚开始的时候我以为这个题需要按顺序依次计算, 故对于每一个rp[i]都有选或者不选两种可能,显然复杂度为O(2^N),用dp写了半天,dalao悠悠地告诉我这是贪心。。。所以吧,还是写代码前先好好想想,别着急动手。

你可能感兴趣的:(【北理乐学】机智的大师)