题意:两个人比赛,得分规则如下:
每个题目的分值如下,
其中的分数代表,解决这道题目的人数占总比赛人数的比例;
每个人可以得的分数如下: 题目分值*(1-此人解决这道题目所用时间/250);
在比赛的所有的人当中有两个人,其中一个人的编号为0,名字为Vasya,另一个编号为1 ,名字为Petya,现在vasya想得到比petya高的分数,他申请了很多个账号来交题,他可以用申请的账号来交他做出来的题目,他没有做出来的题目不能交,现在给出n个人,其中包括vasya和petya,给出每个人解决题目所用的时间,其中一共有5道题目,现在问patya最少需要申请多少个账号可以得到比petya的分数高,如果vasya的分数不能比petya的高输出-1,否则输出所申请的账号数量。
思路:枚举+贪心
枚举:先统计现在每个题目过题的人数,然后在求进入下一档次时所有人的人数。因为每个题目的分值相当于是一个区间,每个分值有一个区间,所以枚举每个题目进入下一个档次所有人的数量。
贪心:为了让vasya的分数比petya的分数高并且需要申请账号的数量进可能的少,有如下贪心策略
- 当vasya没过这个题的时候,此时其他账号也不能过这个题,此时过了这个题目的人数等于原人数
- 当vasya过了这个题并且petya没过这个题的时候,要让分数尽可能的高,所以此时过题的人数等于原人数
- 当vasya题的时间比petya短时,要让这个题目的分数尽可能的高,所以此时过题人数等于原人数
- 当vasya过题的时间比prtya高的时候,要让这个题目的分值尽可能的低,所以此时过题人数等于原过题人数加上现在又加上的人数
代码如下
#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <cstdio>
#include <vector>
using namespace std;
int per[200][5];
int num[5];
int n;
int getscore(int idx,bool is,int nn)
{
if(per[is][idx]==-1) return 0;
int solved=0;
if(per[0][idx]==-1||per[1][idx]==-1||per[0][idx]<=per[1][idx])
{
solved=num[idx];
}
else
{
solved=nn-n+num[idx];
}
int maxn=500;
for(int i=2; i<=32; i*=2)
{
if(solved*i>nn) break;
else maxn+=500;
}
return maxn*(1.0-per[is][idx]/250.0);
}
int main()
{
scanf("%d",&n);
memset(num,0,sizeof(num));
memset(per,0,sizeof(per));
for(int i=0; i<n; i++)
{
for(int j=0; j<5; j++)
{
scanf("%d",&per[i][j]);
if(per[i][j]!=-1) num[j]++;
}
}
vector<int> v;
v.clear();
v.push_back(n);
for(int i=0; i<5; i++)
{
for(int j=2; j<=32; j*=2)
if(num[i]*j>=n) v.push_back(num[i]*j);
}
sort(v.begin(),v.end());
for(int i=0; i<v.size(); i++)
{
if(i&&v[i]==v[i-1]) continue;
int score1=0,score2=0;
for(int j=0; j<5; j++)
score1+=getscore(j,false,v[i]);
for(int j=0; j<5; j++)
score2+=getscore(j,true,v[i]);
if(score1>score2)
{
cout<<v[i]-n<<endl;
return 0;
}
}
cout<<-1<<endl;
return 0;
}