这次比赛打的自闭了,D题和G题做了三四个小时没A,这两个题都是模拟题,但是总是在模拟过程中出一些问题(细节处理不好),这道D题也是模拟题目,但是赛后搜了一下题解,有大佬都不用模拟过程,直接计算,我还是太菜了,你大佬还是你大佬orz。
下面粘一下题目
题目大意是你刚开始有100本金,然后给出n天的股票价格(可以以这个价格买入,也可以以这个价格卖出),但是你手上的股票最多有10w股,求你最多能挣多少钱。
下面说一下大佬代码的思想:都不用开数组来保存每一天股票的价格,直接一边读入一遍处理,即每天都处理当天的股票。核心思想是用一个flag标记一下你买入(或者卖出)股票的价格,如果第二天的价格比flag要高的话就在第二天补上这两天的股票差价。如果第二天的价格比flag要低的话就在第二天买入这个股票。点睛之笔在于这个代码并不是用num+=的形式来记录股票的数量,而是直接用num=当前手里的钱/当天股票的价格,同时sum(手里的钱数)并不会因为买入股票而减少(sum一直是以补差价的形式来加的,即sum+=的形式),这样一来如果以后几天有更便宜的股票你也可以直接购买,这样前一次的num(股票的数目)并不会影响到后面,例如你现在手里有200本金,第一天股票的价格为50,第二天股票的价格为40,第一天你买入的num=200/50=4,同时flag=50(即记录当前买入股票时的价格),但是这并不是最优的方法,因为第二天股票价格更低,所以我们应该在第二天买入,当你输入第二天的股票价格时,由于(40<flag),所以这时候num=200/40=5,这时才是最优方案。
上面说的是买入的思想,其实卖出的思想也是一样,如果flag<x(x代表当天股票价格),就说明现在股票售价比我们买入的时候要高,我们是有利可图的,这时候我们就卖出,同时sum+=num*(x-flag)//这里是以差价的形式增加的,非常奇妙的思想! 例如:第一天股票价格是100,第二天是101,第三天是300,我们一眼可以看出应该在第一天买入,第三天卖出这样可以利益最大化,下面我们模拟一下通过大佬代码的过程,首先我们在第一天买入(价格为100)同时flag=100,第二天价格为101>100,所以我们“卖出”(注意!!!这里的卖出是“伪卖出”,即并不是真正的卖出),同时flag标记为101,这时候我们的sum是101,即原本的100+差价1块。到了第三天,股票价格为300,比第二天的101要大,300>flag,所以sum+=(300-101)*1,300-101是差价,后面的那个*1是有一支股票,所以sum其实是一直以补差价的形式增加的,这也是代码的巧妙之处!!!
最后还有一个重点就是num(股票的数目)的值要用long long,不用long long 会WA,虽然题目说你手上最多有10w股,但是你用sum/x之后会超过int的范围,所以用long long 记录
下面是代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int i,n,x,flag=100;
long long int sum=100,num=0;
scanf("%d",&n);
for(i=0; i<n; i++)
{
scanf("%d",&x);//x代表当天股票的价格
if(x<=flag)
{
num=sum/x;//num用long long 否则会WA
flag=x;
num=min(num,(long long int)100000);//股票最多10w股,不能超过10w股
}
else
{
sum+=num*(x-flag);//补差价
flag=x;
}
}
printf("%lld\n",sum);
return 0;
}
虽然代码很短 但是思想是真的强,我看着代码理解了好一会才理解过来。
--------------------------------分界线----------------------------------
接下来是G题,G题怎么说呢,也是模拟题,但是因为题目是英文,我们队的英语水平不高所以只能读懂大概,很多细节根本不明白,这导致了我们在不完全理解题意的状态下敲了三四个小时没敲出来,惭愧- -!
先粘一下题目
题目大意:就是炉石的排位机制……
共25个等级和传说等级,赢一局一颗星,连续赢三局以上额外多加一颗星(高于5级后不多加星),满星后再多一颗星才能升等级,并且升级后新等级有一颗星。
输一局减一颗星(21-25级输了不扣星,但是仍会断连胜),输了后没星仍可以保持段位,但是没星后又掉星了会掉等级。传说后不论输赢均不掉段。
各等级的星星为
• Rank 25-21: 2 stars
• Rank 20-16: 3 stars
• Rank 15-11: 4 stars
• Rank 10-1: 5 stars
这个题就是纯粹的模拟了,没有像D题那样更”简单“的代码了,我们组问题主要出在了段位下降一次之后星也会少一颗,比如现在是Rank2 0颗星,如果输一次的话就变成了Rank3 1颗星(满星为2颗),我们一直以为是变成Rank3 2颗星,还有一个问题就是段位保护那里边界问题,题目描述是Rank21-25处于段为保护 输了不会掉星,所以我们只考虑了处于段位21-25输的时候不掉星,没考虑到如果是Rank20 0颗星的话会怎么样,实际上如果是Rank20 0颗星同时输掉一次的话应该还是Rank20 0颗星,我们之前没考虑到这个样例,所以根据我们的程序会变成Rank21 2颗星(满星为2颗),所以我们一直在WA并且找不出错误- -
下面是代码:
#include <bits/stdc++.h>
using namespace std;
int main()
{
int a[200]= {0,5,5,5,5,5,5,5,5,5,5,4,4,4,4,4,3,3,3,3,3,2,2,2,2,2};//数组a记录每个段位满星的个数,顺序是逆序的,为了和ranks同步
int ranks=25,starts=0,times=0,i,len;
char str[10010];
scanf("%s",str);
len=strlen(str);
for(i=0; i<len; i++)
{
if(ranks==0)//如果是Rank0的话就说明达到最顶峰了,直接break出去输出Legend就行了
break;
if(str[i]=='W')
{
times++;//连胜+1
starts++;//星数+1
if(times>=3&&ranks>=6&&ranks<=25)//如果连胜>3同时段位没有在5之上的话就触发连胜额外加的那一颗星
starts++;
if(starts>a[ranks])//如果星数>该段位最多星数,即代表晋级段位
{
starts-=a[ranks];
ranks--;//段位上升一个
}
}
else
{
times=0;//终结连胜
if(ranks>=21&&ranks<=25)//处于段位保护状态,输了也没什么操作,所以直接contin
continue;
starts--;//星数-1
if(starts<0)//如果星数为负
{
if(ranks==20)//特殊情况,我们队没有想到的情况
starts=0;
else
{
ranks++;
starts=a[ranks]-1;//掉段之后星数也要再-1
}
}
}
}
if(ranks)
printf("%d\n",ranks);
else
printf("Legend\n");
return 0;
}
总体来说这次比赛做的十分不好,原因主要在于英语不好题意没读太明白(G题),对于一些边界值模棱两可,找不出错误。还有思维上确实还有待提高(D题)。