【写在前面】——在调试了n遍代码之后,终于自己给自己解了毒,也终于可以开始更新我的第一篇博文
【再说几句】——OpenSnow巨佬的影响力非常广泛,在她的带动下,我也决定改题!哈哈哈~,但由于我比较懒,就不粘原题了,直接改喽。
【开始正经】
<题目背景>
众所周知,可爱的乔治是一位能吃的小猪,他经常会把看好的吃的加进自己的购物车里面。而他还小,没有多少零花钱,不舍得吃特别贵的事物。
<题目描述>
就在这时,乔治的姐姐佩奇想要帮助乔治。如果帮乔治买一次事物(即购物车食物的非空子集),佩奇可以得到这次购买食物的最大价值的钱(佩奇也是为了赚点零花钱),而要花费的代价是这次所购买的食物价值的平均值。
乔治因为有了佩奇的帮助,变的越来越贪婪(事实上可爱的乔治才不会这样,都怪这个毒奶的题目),所以每次往购物车里加的东西都会不比购物车中的任何物品价值低。
佩奇想要得到最多的钱,请问她购买一次事物能得到的最大价值是多少(即佩奇当前可以赚的最多零花钱是多少)?
<输入输出格式>
输入格式
第一行有一个整数n,表示操作次数。
第1~n+1行,每行有一个操作类型:如果为1,则还有一个数k,表示乔治这次加入购物车的食物的价值;如果为2,表示佩奇想知道当前的最大收益。
输出格式
对于每一个2操作,输出1行1个4位浮点数,表示当前的最大收益。答案四舍五入。
输入输出样例
数据范围
对于5%的数据,保证和样例一模一样
对于30%的数据,保证n<=2000
对于100%的数据,保证n<=500000
【先粘代码】
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<cstring>
using namespace std;
struct node
{
int a,k;
}t[50005];
int main()
{
//freopen("yjj.in","r",stdin);
//freopen("yjj.out","w",stdout);
int n;
double ave,wei,sum = 2,li; //因为每次都先算好两个食物的平均数,因此sum一开始就为2
scanf("%d",&n);
for(int i = 2;i <= n + 1;i++)
{
scanf("%d",&t[i - 1].a);
if(t[i - 1].a == 1) scanf("%d",&t[i - 1].k);
}
for(int i = 1;i <= n;i++)
{
if(t[i].a == 1) continue;//如果是1操作,则继续
else if(t[i].a == 2)//如果是2操作
{
wei = t[1].k + t[i - 1].k;//先算出第一个食物和这个2操作之前内个食物的总价
ave = wei / sum;//求出两个食物的平均价格
for(int j = 2;j < i - 1;j++)//从第二个食物开始枚举,枚举到倒数第二个食物
{
if(t[j].a == 1 && t[j].k < ave)//如果枚举的当前食物的价格比之前所求的平均值小
{
wei += t[j].k;//就买它
sum++;//食物总数累加1
ave = wei / sum;//求出当前平均值,为下一次比较做准备
}
}
li = t[i - 1].k - ave;//佩奇的收益
printf("%.4lf\n",li);
}
return 0;
}
【胡乱分析】
瑞拉我(对,就是我)做这道题的时候,没有注意到“非空子集”这四个字,导致佩奇把所有食物都买了,然后求收益。这样导致样例1过了样例2就过不了,于是各种改double、int,然后样例2过了样例1又过不了。。。后来经学姐的指点,和被自己的毒气快要击毙的时候,写对了代码。。。
那么这道题怎么做呢?首先,关注的点不应该是四舍五入(它好像会自己四舍五入),而是非空子集上,佩奇并不是傻到把所有食物都买,所以这是一道贪心题。读入数据完毕后,先不着急算,开始进入一个循环,直到遇到2操作,然后把第一个食物和最后一个食物的价值加起来,再取平均值,因为这两个食物肯定是要选的(一个最大,一个最小),接下来从第2个食物开始枚举,一直到倒数第二个食物,其中,如果枚举到的食物的价值比当前平均值小的话,就买了它,这样它会拉低平均值(就像你拉低班级平均分。。额开个玩笑),这样佩奇花的钱就少了,如果比当前平均值大,当然是不买了。这道题的思路就是这样。
【orz】
如果哪个地方写错了,或者emmmm,还请大佬尽情鄙视我,要是能回复就更好了。(或者有没有更简短的代码啥的)