早起起来赶TC,工作日早上9点的这场SRM是最容易睡过头的。注册时发现panda教主已经注册了,Petr还没来。但事实的情况是比赛开始时Petr来了,panda教主迟到。
打开题目发现是250和450,预感过500pt的机会来了。果然生平第二次过了SRM的500pt,尽管是一道简单的。总的来说两道题都是想的成份比较多,实现相对简单,今天一共就写了十几行代码就完事了。由于RP大爆发,取得了前所未有的21名的排位,rating也顺势涨到了1888,创出历史新高,还顺带赢了panda教主一场。话说neal_wu非常神奇,coding phase结束的时候,我领先了他225分,但是在challenge phase他大杀四方,连cha成功6个,并且这是本房间有且仅有的六个错误提交,于是我只能眼看着大好局势拱手让人。
流水账毕,以下是详细的题解:
250pt: 转换一下题意,大致是:有n个(2<=n<=14)被涂成A或B的格子,Alice和Bob每次轮流从这些格子里面拿走连续的一些格子(但是不能拿走所有的格子)。最后剩下的格子如果是A,那么Alice就获胜了,反之Bob获胜。每次都是Alice先行动,问给定初始状态,在理想情况下,谁能获取游戏的胜利。
首先思考初始情况,很显然,如果第一个字母是A的话,Alice必胜,因为她可以把剩下的字符串都拿掉,只留下A。同理,如果最后一个字母是A的话,也是Alice胜。于是,只有当两端字母同时都是B时,才能轮到Bob行动。在这种情况下,Alice有两种策略,1是拿走一端的B以及和它连着的若干个其他字符,如此,Bob下次行动时只要拿走剩余的所有字符,留下另一端的B即可获胜。2是Alice不动两端的B,在中间截取一段。如此,局面会变成类似于BXXX___XXXXB (也可能没有X)。Bob的策略也很简单,把其中的一段XXX拿走,剩下一个端点B。接下来如果Alice拿走单个B,Bob就获胜,如果Alice在右边那串里拿,Bob只要想办法尽快把那串拿完就能获胜(如果Alice试图把右边的串分成两段,Bob就拿走两段中的一段,直到剩下的串拿完为止)。于是,程序只有两行:
if(cells[0]==’A’ || cells[cells.size()-1]==’A’) return “Alice”;
else return “Bob”;
450pt: 给你一个错误的等式a*b=c (a,b,c都为1 – 10^9的正整数),将其修正为正确的等式A+B=C,使得 | A-a | + | B-b | + | C-c | 最小。求出这个最小值。
如果做过上海赛区hl大神的A题,看到这题的时候一定会觉得很熟悉吧。a,b,c的范围都大到吓人,直接枚举肯定会挂掉。所以此题肯定是要用某一种trick,将10^9的问题简化为复杂度更小的问题。
首先来看要枚举的变量,假定我们通过枚举确定了A,这时,随着B的变化,我们的diff = | A-a | + | B-b | + | C-c | 有且仅有一个极小值,而且这个极小时会出现在C接近于c的地方。所以我们只须试验B=c/A和B=c/A+1这两个值就可以算出当前A的最小diff值了。现在我们有了一个O(10^9)的算法,即枚举A=1…10^9,通过上述办法计算最小的diff值。前面提到的上海赛区的A題的技巧就在这里出现了:由于A*B = C,事实上A和B里面总有一个是小于等于sqrt(C)的,只需要枚举小的那个数就可以了,这样复杂度就降低为O(sqrt(10^9))了。实现的话,首先看a和b的大小,如果a>b的话就swap一下。枚举的时候暴力一点,直接枚举1到40000而不要去计算sqrt(c)会避免很多麻烦,还有所有的计算结果用long long来保存以避免乘法的时候溢出,应该就可以过了。
1000pt: 不会 >.< 以后补上