本次欢乐赛挺简单的nia~
第一次抢到欢乐赛首 AK,真棒。
T1
模拟即可。如果 n≥99n\geq 99n≥99,输出 99+;否则输出 nnn。
T2
模拟即可*2。如果 n>0n>0n>0,输出 YES,否则输出 NO。
T3
模拟即可*3,但是更复杂了。仔细读题:
> 那么他会给你这 kkk 杯奶茶中的每一杯打 777 折(向下取整)哦~
也就是说,打折后的单价为 ⌊0.7×v⌋\lfloor0.7\times v\rfloor⌊0.7×v⌋,这 kkk 杯的总价是 k×⌊0.7×v⌋k\times\lfloor0.7\times v\rfloork×⌊0.7×v⌋ 而不是 ⌊k×0.7×v⌋\lfloor k\times0.7\times v\rfloor⌊k×0.7×v⌋,单价要先取整再乘数量!
然后我们要买 nnn 杯奶茶,这 nnn 杯奶茶中有几个 kkk 杯奶茶呢?当然是 ⌊nk⌋\lfloor \dfrac nk\rfloor⌊kn ⌋。剩下的 n mod kn \bmod knmodk 杯奶茶就需要按原价 vvv 元购买。总价即为 ⌊nk⌋×k×⌊0.7×v⌋+(n mod k)×v\lfloor\dfrac nk\rfloor\times k\times\lfloor0.7\times v\rfloor+(n \bmod k)\times v⌊kn ⌋×k×⌊0.7×v⌋+(nmodk)×v。
最后与 mmm 比较输出即可。
T4
疑为错题。输入数据量最大约为 10910^9109 字节的数量级。
当然数据水,我们的普通程序优化一下就过了,注释在代码里。
T5
可以任意次交换字符串中任意两个字符的位置,换句话说就是可以随意重排这个字符串。因此考虑把两个字符串变为有序,相同即为 YES,不同即为 NO。
实现时可以考虑使用桶计数字符。
T6
吐槽在前,数据过水。考虑这份显然错误的桶计数的代码:
输入:
代码的输出:YES,显然错误。最离谱的还是这份代码能 AC,所以数据确实应该加强。
本题正解应为循环与双指针。初始 ps 与 pt 分别取 sss 与 ttt 的串首,每一次循环贪心地移动 pt 至下一个 ttt 中与 ps 指向的字符相同的位置,随后 ps 与 pt 均需自增。若 pt 已经指向串尾,ps 仍失配,则 sss 不是 ttt 的子序列,否则是。时间复杂度 O(n)O(n)O(n)。
T7
某人刚想开始打十六进制转十进制,忽然看见这句话:
> 如果你知道某些技巧的话,这道题会非常简单。
某人快速思索,想起了 C 风格输入输出有一个神奇的类型限定符:%X。这个限定符可以输入输出十六进制数,真神奇!
于是这就变成了 a+b problem。
某人试了样例,发现输出少了前缀 0X。这好办,输出时多加一个 0X 前缀就行了。
所以这仍然是 a+b problem。
T8
本次欢乐赛的压轴题,还是挺有难度的。暴力显然不行,因为 O(n)O(n)O(n) 在 n=1018n=10^{18}n=1018 下会超时。看起来是数学题,所以直接去想 O(1)O(1)O(1)。
首先问题好像很吓人,可以先容斥一波。[x,y][x,y][x,y] 中不能被 aaa 整除且也不能被 bbb 整除的数的个数,即为 [x,y][x,y][x,y] 中数的个数,去掉能被 aaa 整除的,再去掉能被 bbb 整除的。这时能同时被 aaa 和 bbb 整除的就被算了两遍,要再加一遍,即再加上能同时被 aaa 和 bbb 整除的。小学数学告诉我们能同时被 aaa 和 bbb 整除相当于能被 lcm(a,b)\operatorname{lcm}(a,b)lcm(a,b) 整除。所以问题分为四部分:
* [x,y][x,y][x,y] 中数的个数
* [x,y][x,y][x,y] 中能被 aaa 整除的个数
* [x,y][x,y][x,y] 中能被 bbb 整除的个数
* [x,y][x,y][x,y] 中能被 lcm(a,b)\operatorname{lcm}(a,b)lcm(a,b) 整除的个数
第一个问题的答案显然是 y−x+1y-x+1y−x+1。现在考虑后面三个问题。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
提示:接下来的这一段讨论中诸变量的意义与前文不同,请不要混淆。
要知道,一个连续区间中,一个数 xxx 的倍数分布是等差的,公差为 xxx。所以使用等差数列的性质,我们需要的答案项数即为(首末项之差)÷x+1\div x+1÷x+1。而首项就是大于等于左端点的最小的 xxx 的倍数,末项就是小于等于右端点的最大的 xxx 的倍数。令左端点为 lll,右端点为 rrr,首项为 aaa,末项为 bbb,根据倍数的定义,则有:
{⌈lx⌉x=a⌊rx⌋x=b\begin{cases} \lceil\frac lx\rceil x=a\\ \lfloor\frac rx\rfloor x=b \end{cases} {⌈xl ⌉x=a⌊xr ⌋x=b
可以试着去理性理解一下这个式子,应该可以理解。
由此得出结论:在 [l,r][l,r][l,r] 中,能被 xxx 整除的数有 (⌊rx⌋x−⌈lx⌉x)÷x+1(\lfloor\frac rx\rfloor x-\lceil\frac lx\rceil x)\div x+1(⌊xr ⌋x−⌈xl ⌉x)÷x+1 个。可继续化简,当然不化简也没问题。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
有了这个结论,后三问便可解决。相信写代码就不是难事了,接下来说几个坑。
1.不开 ____ ____ 见祖宗。不用我说罢。
2.过程中涉及浮点运算。而数据范围是 101810^{18}1018,最大有效位数达到了 191919,此时使用 double 类型会导致丢精度,然后听取 WA 声一片。正确的做法是使用 long double 类型,当然将过程中的浮点运算全部化为整形运算也不失为一种好的选择。
代码:
后记
T4 数据范围什么鬼?如果想卡空可以改空间限制吧。