其实这道题是个签到模拟,但是我因为小细节错了没有第一次AC,后来hack了数据debug才找出来有俩个地方代码顺序交换错误了····
题目
Sample Input
10
600 600 600 600 600 600 600 600 500 550
Sample Output
0 0 0 0 0 0 0 0 2 2
题解
这里首先要注意输出格式,是不换行的···我当初第一发PE炸掉···
题目意思很简单,就是先把牌子数按照比例计算好,如何根据得分情况分牌子。直接跑模拟就好了,就是要注意存储数据的三个点,每个分数的人数段,排名情况以及获奖情况,然后根据排名情况分奖牌。
代码注释写的很清晰,可以直接看
AC代码
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pre(i,a,b) for(int i=a;i>=b;--i)
#define m(x) memset(x,0,sizeof x);
#define ll long long
const int maxn = 2e6+5;
//初始数据
int ori[maxn];
bool cmp(int a,int b){
return a>b;
}
//f存储各分数段的人数,save存储哪些分数出现过,s存储分数的获奖情况
int f[1010],save[1010],s[1010];
int main()
{
//f存储各种牌子的数量
int f1,f2,f3;
int n,x,k;
while(~scanf("%d",&n)){
memset(s, -1, sizeof(s));
memset(f, 0, sizeof f);
memset(save, 0, sizeof save);
k = 0;
f1 = 0.2*n;
f2 = 0.3*n;
f3 = 0.5*n;
// cout << f1 << " " << f2 << " " << f3 << endl;
for(int i=0;i<n;++i)
{
scanf("%d",&x);
ori[i] = x;
f[x]++;
if(f[x]==1)
save[k++] = x;
}
//逆序排序,分高的优先拿牌子
sort(save,save+k,cmp);
for(int i=0;i<k;++i)
{
// cout << "f[[save[i]]]" << "=" <<f[save[i]] << endl;
//如果金牌还有
if(f1){
//金牌够用
if(f1-f[save[i]]>=0){
s[save[i]] = 0;
f1 -= f[save[i]];
}
//金牌不够发,借银牌来发
else if(f1+f2-f[save[i]]>=0)
{
//金牌直接消耗完,消耗银牌
s[save[i]] = 0;
//这里就是要注意f1=0要放在这行下面,不然出事
f2 = f2 - (f[save[i]]-f1);
f1 = 0;
//金牌银牌都不够发,把铜牌份额发了
}else if(f1+f2+f3-f[save[i]]>=0)
{
s[save[i]] = 0;
f3 = f3 - (f[save[i]]-f1-f2);
f1 = 0;
f2 = 0;
}
}
//没金牌了,发铜牌
else if(f2)
{
//银牌够发
if(f2-f[save[i]]>=0){
s[save[i]] = 1;
f2 -= f[save[i]];
//银牌不够发,消耗铜牌份额
}else if(f2+f3-f[save[i]]>=0)
{
s[save[i]] = 1;
f3 = f3 - (f[save[i]]-f2);
f2 = 0;
}
}
else s[save[i]] = 2;
// cout << f1 << " " << f2 << " " << f3 << endl;
}
for(int i=0;i<n;++i)
{
if(i!=n-1)printf("%d ",s[ori[i]]);
else printf("%d",s[ori[i]]);
}
}
return 0;
}
细节问题WA3发真的脸黑···