——一句20分的if,一个60分的%d
和+
,两个2.5分的等号和一个炸了65分的人的故事。
这句话官方数据出来以后就没有那么震撼了。
原句:
一句30分的if,一个60分的运算符,两个25分的等号和一个炸了155分的人的故事。
比赛过程
14:30~14:35
监考员在黑板上写了密码,输入了3次才得知某一个写成0的符号是O,再输入了2次才得知前后的括号是密码的内容。
14:35~16:00
点开题目,发现T1是一道看起来很恶心的大模拟题。反正无论如何我都要切掉这道题的,就直接开打了。
先用一个暴力跑出1582年10月4日所对应的儒略日,然后以此为分界点将日期分开。
接着对于1582年10月4日前的日子,直接把公元前4713年1月1日当成0年1月0日来处理,发现这时闰年极其好处理。把天数缩小到4年以内时再把它缩小到1年以内,接着暴力。
最后把小于4713的年份减去4713,大于4713的年份减去4712大概就可以了。
接下来是1582年10月15日以后的日子,一开始想法是先处理1582年10月15日到1584年1月1日(为什么不是1583年,是因为1584年是个闰年,方便后面的处理)的这个区间,再处理1584年1月1日到1600年1月1日这个区间,最后处理1600年以后的年份。
而在年份的处理上,要先缩小到400年以内,再缩小到100年以内,接着是4年、1年,最终锁定日期。细节繁琐,打到16:00时觉得这题要先放一放了,不然后面的题估计都得没分。于是就先做后面的题目了。
16:00~17:30
发现T2是一道真正意义上的签到题。
求出动物一共覆盖了多少个二进制位(记为
x
x
x),接着答案就等于
2
x
−
t
2^x -t
2x−t,其中
t
t
t表示
n
n
n个动物中
2
x
−
1
2^x -1
2x−1的子集个数。其实
t
t
t一定是等于
n
n
n的,但是我当时没有意识到这一点,这也为后来炸了二十几分埋下了伏笔。至于
q
q
q,完全是没有用的,扔掉就好了。还有可能
x
=
64
x=64
x=64,我发现在unsigned long long
条件下,
0
−
n
u
m
=
2
64
−
n
u
m
0-num=2^{64} -num
0−num=264−num,因此只用把
a
n
s
=
2
64
ans=2^{64}
ans=264的情况特判掉就可以了。
T3只会30分暴力,因此直接线段树模拟就好了。
T4只要考虑一条蛇如果吃掉另一条蛇后,将来会不会被其它蛇吃掉就好了。但是我当时的做法存在问题:比如当前蛇的能力值从高到低是(不考虑相等的情况):
a
1
,
a
2
,
a
3
,
⋯
,
a
n
a_1,a_2,a_3,\cdots ,a_n
a1,a2,a3,⋯,an,然后现在1号想要吃掉n号,我就记
a
1
′
=
a
1
−
a
n
a_1'=a_1 -a_n
a1′=a1−an,看这时2会不会把1吃掉……
但是一条蛇被吃掉的条件是它为最后一名啊!!!
17:30~18:00
发现T1可以直接模拟出400年内的年月日,这样就极大地便利了计算的过程。
接着就先把天数缩小到400年以内,再使用预处理出来的结果就好了。
18:00~18:20
T1开始测样例。
很快,小样例全过了。现在只剩下大样例了。
由于不会用cmd或power shell的文件比较命令,我就自己打比较程序。
一开始的打法是先读入所有的数字,再进行比较。但是这样子会把BC前的数字重复读入。
于是改变打法,想要对于每一行,都先分别打开两个文件,再进行比较。然而这样光是打开文件的时间就很大了。
最后想到把每一行读入,然后压缩成一个长长的字符串,再把两个字符串进行比较。接着发现我过了。
但是现在只剩下10分钟了。已经没有时间打对拍了。
18:20~18:30
先完善了考生的txt
文件,再检查每一道题目,把 编译选项-代码生成/优化-显示最多警告信息(-Wall) 打开。结果发现T1把long long
类型用%d
输出了。
改过来之后跑了一下check.exe
,接着等了一下比赛就结束了。
出考场时感觉良好,觉得应该有200分,最高是100+100+30+40=270。
赛后
以下的分数都是基于民间数据。
我炸了。
在洛谷上测了一下,T1莫名10分,T2莫名80分,T3、T4竟然都只有25分?!
测了另外的民间数据,T1还是10分,T2变成了75分,T3有30分,T4居然0分了。
这次估计就120左右吧……
检查了一下,T2我在判断二进制数a[i]
是否是sum
的子集时,是这样子写代码的:
if(choose&a[i]) ...
但是如果
a
[
i
]
=
0
a[i]=0
a[i]=0我就会挂掉……
应该这样子写:
if((choose&a[i])==a[i])
这两个个等号值25分。
至于T1,错得就更坑了!
我1582年10月4日前的日期错掉了,本该是28 2 4713 BC
的我输出了0 3 4713 BC
。
检查了一下,发现我在确定一年内的日期时,是这样子跑的:
然后如果是闰年且m=2,n=28,我就会把n减成-1,m加成3。
把这个bug补上就40分了。
接着在后面发现我在访问第m月的天数的数组时,由于下标是从0开始的,因此要把m减去1。
然而我把-
打成了+
,炸了60分……
于是乎T1就没了90分,这是我最大的失误。因为这并不是方法上的问题,而是实现上的问题;T4那是方法上的问题,倒也没那么严重。
总结
这次比赛主要反映了我以下几点问题:
- 先说好的,时间规划上比较合理。在16:00把T1放一放是一个很明智的选择;
- 代码实现错误太多了,一些小细节很容易打挂。一定要静下心来,即便某道题很水,代码很短,我很有把握,也要认真地肉眼差错、对拍;
- 对拍技巧不行。这次我因为不会用cmd中的fc命令比较文件而失去了二十分钟。平时要多多练习对拍技巧,凡是可以拿到的分都不能丢失!
- 平时模拟赛时就极容易写挂代码,这样在考场上毫无疑问是会挂掉的。平时要争取把代码的实现准确度提升。因此,在改题的时候,也要坚持打一段代码就肉眼差错一下,敲完之后再过一过,接着才测样例。
后记
2020.11.16
今天官方数据放了出来,测了一下,40+95+50+20=205。
这个数据很水,有的人T1一堆bug都能拿100,T3暴力就有70了。
虽然我的分数变高了,但是因为大家的分数都增加了,我可能变得更不利。希望能进复赛吧。
2020.11.20
昨天看到了成绩,惊异地发现T1只有20!出题人身后的日期全都没有分了。
一开始以为是数组越界全都没分,但是又不甘放弃加上20分的希望。
据说LOJ上有noi的测试环境,于是交了一下——然后真的就只有20。
后来我又提交了我在gmoj和洛谷上AC的代码,结果只有40分?!!
找了半天,原来是我用%lld
输出int
类型了。