Fate/Beihang OO第一话——第一单元总结
概况
2020年,圣杯突然出现在了北京航空航天大学,北航数百6系学子意外被卷入圣杯战争。在这场特殊的圣杯战争中,没有刀光剑影,没有殊死搏斗,有的只是满空飞舞的头发和“嗒嗒嗒”的BGM。
闲话不提,第一单元的面向对象(没有对象)学习终也落下了帷幕,而我也成功重构三次完成了任务,而这是我对我的成果做的一个总结。我以前从未接触过JAVA语言,而学习探索一门语言往往是充满刺激、快乐与成就感,同时又充满困难、挫折和头发,这些酸甜苦辣共同构成了我这一个月以来轰轰烈烈的战斗史。
接下来便开始总结吧。
一、英灵概况——程序分析
1. 第一次作业
第一次作业很简单,此时没有对象也不清楚怎么面向对象的我直接选择了面向过程编程,类也就只有两个,其中一个还是main。
我将多项式拆开储存在Poly当中,Poly类有俩参数,指数和系数,常数则对应指数为0。
当时的我追求性能分,把重点花在了输出上,最后也成功在互测中得到了满分。
1.1 基于度量的程序结构分析
| class | OCavg | WMC | CSOA | LOC |
|---|---|---|---|---|
| Main | 9.0 | 9.0 | 13.0 | 59.0 |
| Poly | 3.83 | 23.0 | 20.0 | 83.0 |
| Total | 32.0 | 33.0 | 142.0 | |
| Average | 4.57 | 16.0 | 16.5 | 71.0 |
| method | ev(G) | iv(G) | v(G) | CONTROL | LOC |
|---|---|---|---|---|---|
| Main.main(String[]) | 3.0 | 9.0 | 9.0 | 9.0 | 57.0 |
| Poly.add(String) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Poly.ifz() | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Poly.out() | 2.0 | 10.0 | 10.0 | 9.0 | 36.0 |
| Poly.outFirst() | 2.0 | 9.0 | 9.0 | 8.0 | 29.0 |
| Poly.Poly() | 1.0 | 1.0 | 1.0 | 0.0 | 2.0 |
| Poly.Poly(String,String) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Total | 11.0 | 32.0 | 32.0 | 26.0 | 136.0 |
| Average | 1.57 | 4.57 | 4.57 | 3.71 | 19.3 |
因为完全没有考虑到今后的扩展性,所以本次作业写得非常简单粗暴,所以也没什么复杂度可以分析的。
UML类图

1.2 应用对象创建模式
这一次作业中除了把每个项象征性地装起来之外,没有任何面向对象的成分所在。
当时天真的我对JAVA的语法尚且不太熟悉,对什么类什么方法更是半知半解。于是,我直接将表达式解析过程直接写进了main方法里,为此被checkstyle重拳出击,花了好久才把65行缩短到了60行(后来,我学会了static method,暴风哭泣)。
在解析完成之后,将对各项的求导、输出等过程分别写成了Poly类的方法。事实上,我的处理方法和以前C语言课程时面向过程并无本质区别,“对象”等同于结构体,“方法”等同于函数。这样一来,这道题倒是轻轻松松写完了,然而根本没有给后面的作业留下任何拓展空间。
当然,我觉得提前剧透没意思,所以也没怎么调查后面会有什么拓展,所以也根本没有做出尝试(说白了就是懒)。
1.3 BUG分析
本次作业一没有WF的判断,二又结构简单,所以我基本没有出现BUG,并在互测中得到了满分。
但在互测中,我因为对输出情况的疏忽被hack了一个点(出现条件极其苛刻,真的佩服)——当系数为±1时,若指数为0,则输出±1,然而在指数不为零时,我却忘记了输出正负号。在自测的时候,我改正了负号的疏忽,却忘记了正号,这导致了错误的发生。
事实上,还留下了隐患——我在处理空白字符时直接替换了\s,导致了第二次作业WA在了垂直制表符上。
1.4 心得体会
当我看到自己强测100的时候惊了,这也让我认识到强测也不是强炸天。
在次周星期三的研讨会上,听了几位大佬的分享收获很多,那时自己才对面向对象编程有了直观的认识,而这也让我在写接下来两次作业时少走了许多弯路。
2. 第二次作业
面向过程的我在看到第二次作业时便傻了眼,仿佛自己做了P0就做P5了一样,无从下手、啥都不会!更要命的是,那一周的我被其他要紧事缠得脱不开身,忙得连担心自己没时间搞OO的时间都没有。还好这时大佬救命捞了我一手——周三晚的研讨课给了我很大的启发,这也能让我在后面比较快地完成作业。我在周五晚才好歹忙完一段落,开始构思、动手,最后在28点完成了代码。
事实上,在写完之后,我发现虽然自己构思的时候似乎非常“对象”,然而却越写越“过程”,其实只完成了一点点的抽象化。我用了许多个类分别封装幂函数、三角函数、常数、项,然而大家其实都一样——本质上都是四元组。我只是避免了将所有类型搅成一团,求导、输出分一大堆情况的惨状,歪打正着地完成了一点解耦合的工作。
2.1 基于度量的程序结构分析
| class | OCavg | WMC | CSOA | LOC |
|---|---|---|---|---|
| Cos | 1.25 | 5.0 | 40.0 | 24.0 |
| Digit | 1.45 | 29.0 | 36.0 | 121.0 |
| Item | 1.5 | 6.0 | 41.0 | 57.0 |
| Main | 3.2 | 16.0 | 17.0 | 102.0 |
| Mi | 1.4 | 7.0 | 41.0 | 31.0 |
| Poly | 1.5 | 12.0 | 48.0 | 56.0 |
| Sin | 1.25 | 5.0 | 40.0 | 23.0 |
| Total | 80.0 | 263.0 | 414.0 | |
| Average | 1.6 | 11.43 | 37.57 | 59.14 |
| method | ev(G) | iv(G) | v(G) | CONTROL | LOC |
|---|---|---|---|---|---|
| Cos.Cos() | 1.0 | 1.0 | 1.0 | 0.0 | 2.0 |
| Cos.Cos(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Cos.Cos(String) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Cos.diff() | 2.0 | 3.0 | 3.0 | 1.0 | 12.0 |
| Digit.add(Digit) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.deO() | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Digit.diff() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.Digit() | 1.0 | 1.0 | 1.0 | 0.0 | 2.0 |
| Digit.Digit(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.Digit(BigInteger,BigInteger,BigInteger,BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 7.0 |
| Digit.Digit(String) | 1.0 | 1.0 | 1.0 | 0.0 | 6.0 |
| Digit.equals(Object) | 1.0 | 3.0 | 3.0 | 0.0 | 6.0 |
| Digit.getCoef() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.getIndex() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.getIndexC() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.getIndexS() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.hashCode() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.multi(Digit) | 1.0 | 1.0 | 1.0 | 0.0 | 10.0 |
| Digit.on(Digit) | 1.0 | 1.0 | 1.0 | 0.0 | 6.0 |
| Digit.outD() | 2.0 | 16.0 | 16.0 | 9.0 | 38.0 |
| Digit.setCoef(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.setIndex(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.setIndexC(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.setIndexS(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Item.addI(Digit) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Item.diff() | 1.0 | 2.0 | 2.0 | 1.0 | 42.0 |
| Item.Item() | 1.0 | 1.0 | 1.0 | 0.0 | 2.0 |
| Item.outI() | 1.0 | 2.0 | 2.0 | 1.0 | 7.0 |
| Main.findWF(String) | 1.0 | 2.0 | 2.0 | 1.0 | 17.0 |
| Main.main(String[]) | 1.0 | 11.0 | 11.0 | 10.0 | 63.0 |
| Main.mod(String) | 1.0 | 1.0 | 1.0 | 0.0 | 14.0 |
| Main.print(Object) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Main.println(Object) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Mi.diff() | 2.0 | 3.0 | 3.0 | 1.0 | 9.0 |
| Mi.Mi() | 1.0 | 1.0 | 1.0 | 0.0 | 2.0 |
| Mi.Mi(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Mi.Mi(BigInteger,BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Mi.Mi(String) | 1.0 | 2.0 | 2.0 | 1.0 | 10.0 |
| Poly.addP(Digit) | 1.0 | 2.0 | 2.0 | 1.0 | 9.0 |
| Poly.deOut() | 1.0 | 1.0 | 1.0 | 0.0 | 8.0 |
| Poly.out() | 1.0 | 2.0 | 4.0 | 3.0 | 17.0 |
| Poly.out1() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Poly.out2() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Poly.out3() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Poly.Poly() | 1.0 | 1.0 | 1.0 | 0.0 | 2.0 |
| Poly.Poly(Digit,Digit,Digit) | 1.0 | 1.0 | 1.0 | 0.0 | 5.0 |
| Sin.diff() | 2.0 | 3.0 | 3.0 | 1.0 | 11.0 |
| Sin.Sin() | 1.0 | 1.0 | 1.0 | 0.0 | 2.0 |
| Sin.Sin(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Sin.Sin(String) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Total | 54.0 | 89.0 | 91.0 | 30.0 | 391.0 |
| Average | 1.08 | 1.78 | 1.82 | 0.6 | 7.82 |
可以明显看出,我分了很多类,但其实本质都是一个——四元组。复杂度看上去不高的原因就是因为被分担了,实际上是“虚低”。
至于那个Digit里面很复杂的outD方法,那是我在输出时为了化简,把所有“项”合成了一个四元组试图提高性能分。
UML类图

扩展DIT
各种函数继承于Digit类,Digit类基本同时充当了“接口”的作用。
2.2 应用对象创建模式
选择了把不同类型的函数分装,在分析表达式的时候还用上了类似工厂模式的方法,不过没有把工厂独立出来。我用正则表达式分析表达式,先将式子拆成数个项,最后再将项拆成各个因子。判断WF也用的正则表达式“判对”。
依然没有考虑拓展性,因为没有时间。这一次的作业可以说是见招拆招,得分就万万岁了。
2.3 BUG分析
本次作业出现了两个BUG:
- 判断WF时去掉了所有\s,没有考虑非法空白符的情况
- 优化输出时竟然直接字符串替换"x**2"->"x*x",直接导致x**21一类光荣牺牲
两个错误都是考虑不周全的错,而第二个错误则是画蛇添足。
2.4 心得体会
这一次作业让我学到了许多。
- 浅拷贝、深拷贝。虽然这时我还没有了解这些是什么意思,但我至少已经体会到了对引用类型来说,单纯的赋值只是地址的交接,实际上指向的是一个对象。这让我吃了不少苦头,BUG修了老半天。
- 我这次由于时间和精力原因,基本没有进行测试,这也埋下了祸根。
- 不要画蛇添足,一切修改都要充分考虑后再进行。
- 自己的英语属实捉急,起名全是乱起(比如项用的Item),没有用拼音大概是最后的倔强了吧(Mi就是拼音)。
3.第三次作业
第三次作业是表达式求导迭代的最终进化体,加上了嵌套和比较复杂的WF判断。虽然代码完全重构,但有了前两次思路的支撑,这一次的构思并没有花上多少时间。
因为自知能力不足,所以一开始是准备完全放弃优化的。可后面看到
$$
(((0)+0)+0sin((0))+0(0)1cos((0)))
$$
这种实在是浑身难受,于是决定把幂函数和常数合并了、括号适当去除。
3.1 基于度量的程序结构分析
以下是含simplify方法的度量。
| class | OCavg | WMC | CSOA | LOC |
|---|---|---|---|---|
| Basic | 1.0 | 4.0 | 20.0 | 18.0 |
| Cos | 1.8 | 18.0 | 32.0 | 89.0 |
| Digit | 1.14 | 8.0 | 27.0 | 30.0 |
| Eno | 1.71 | 12.0 | 21.0 | 71.0 |
| Item | 4.29 | 30.0 | 28.0 | 147.0 |
| Main | 1.0 | 1.0 | 13.0 | 5.0 |
| Mi | 1.875 | 15.0 | 29.0 | 58.0 |
| Null | 1.0 | 4.0 | 24.0 | 14.0 |
| Poly | 3.0 | 27.0 | 30.0 | 140.0 |
| Sin | 1.8 | 18.0 | 32.0 | 88.0 |
| Total | 137.0 | 256.0 | 660.0 | |
| Average | 2.04 | 13.7 | 25.6 | 66.0 |
这次用了一个“Basic”接口提供求导和toString方法(以及simplify),Main里有许多静态方法,对表达式进行预处理。Eno是一个简化用的类。其他的就是因子、项、表达式类,全部实现Basic。
具体思路见3.2。
| method | ev(G) | iv(G) | v(G) | CONTROL | LOC |
|---|---|---|---|---|---|
| Basic.Basic() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Basic.Basic(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Basic.getCoef() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Basic.setCoef(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Cos.Cos(Basic) | 1.0 | 1.0 | 1.0 | 0.0 | 5.0 |
| Cos.Cos(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Cos.Cos(BigInteger,BigInteger,Basic) | 1.0 | 1.0 | 1.0 | 0.0 | 5.0 |
| Cos.Cos(BigInteger,String) | 1.0 | 1.0 | 1.0 | 0.0 | 6.0 |
| Cos.diff() | 2.0 | 1.0 | 2.0 | 1.0 | 13.0 |
| Cos.getIndex() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Cos.ifWF(String) | 1.0 | 2.0 | 2.0 | 1.0 | 16.0 |
| Cos.setIndex(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Cos.simplify() | 3.0 | 3.0 | 3.0 | 2.0 | 10.0 |
| Cos.toString() | 3.0 | 4.0 | 5.0 | 4.0 | 20.0 |
| Digit.diff() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.Digit() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.Digit(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.Digit(String) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Digit.mulD(Digit) | 1.0 | 1.0 | 1.0 | 0.0 | 5.0 |
| Digit.simplify() | 2.0 | 1.0 | 2.0 | 1.0 | 8.0 |
| Digit.toString() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Eno.Eno() | 1.0 | 1.0 | 1.0 | 0.0 | 2.0 |
| Eno.Eno(List,String) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Eno.getElements() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Eno.getPoly() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Eno.preWF(String) | 1.0 | 5.0 | 5.0 | 4.0 | 36.0 |
| Eno.println(String) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Eno.pro3() | 1.0 | 3.0 | 3.0 | 1.0 | 16.0 |
| Item.diff() | 1.0 | 4.0 | 4.0 | 3.0 | 15.0 |
| Item.Item() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Item.Item(Basic) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Item.Item(String,List) | 1.0 | 10.0 | 10.0 | 9.0 | 48.0 |
| Item.mulI(Basic) | 1.0 | 2.0 | 2.0 | 1.0 | 11.0 |
| Item.simplify() | 4.0 | 11.0 | 11.0 | 9.0 | 38.0 |
| Item.toString() | 1.0 | 2.0 | 2.0 | 1.0 | 7.0 |
| Main.main(String[]) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Mi.diff() | 2.0 | 2.0 | 2.0 | 1.0 | 7.0 |
| Mi.getIndex() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Mi.Mi() | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Mi.Mi(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Mi.Mi(BigInteger,BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Mi.setIndex(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Mi.simplify() | 3.0 | 2.0 | 3.0 | 2.0 | 11.0 |
| Mi.toString() | 3.0 | 4.0 | 5.0 | 4.0 | 19.0 |
| Null.diff() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Null.Null() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Null.simplify() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Null.toString() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Poly.addP(Item) | 1.0 | 1.0 | 1.0 | 0.0 | 6.0 |
| Poly.addP(Poly) | 1.0 | 1.0 | 1.0 | 0.0 | 6.0 |
| Poly.diff() | 1.0 | 2.0 | 2.0 | 1.0 | 7.0 |
| Poly.ifWF(String) | 1.0 | 2.0 | 2.0 | 1.0 | 27.0 |
| Poly.Poly() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Poly.Poly(String) | 1.0 | 2.0 | 2.0 | 1.0 | 20.0 |
| Poly.preDo(String) | 2.0 | 3.0 | 9.0 | 8.0 | 36.0 |
| Poly.simplify() | 3.0 | 6.0 | 7.0 | 6.0 | 25.0 |
| Poly.toString() | 1.0 | 2.0 | 2.0 | 1.0 | 7.0 |
| Sin.diff() | 2.0 | 1.0 | 2.0 | 1.0 | 11.0 |
| Sin.getIndex() | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Sin.ifWF(String) | 1.0 | 2.0 | 2.0 | 1.0 | 17.0 |
| Sin.setIndex(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 3.0 |
| Sin.simplify() | 3.0 | 3.0 | 3.0 | 2.0 | 10.0 |
| Sin.Sin(Basic) | 1.0 | 1.0 | 1.0 | 0.0 | 5.0 |
| Sin.Sin(BigInteger) | 1.0 | 1.0 | 1.0 | 0.0 | 4.0 |
| Sin.Sin(BigInteger,BigInteger,Basic) | 1.0 | 1.0 | 1.0 | 0.0 | 5.0 |
| Sin.Sin(BigInteger,String) | 1.0 | 1.0 | 1.0 | 0.0 | 6.0 |
| Sin.toString() | 3.0 | 4.0 | 5.0 | 4.0 | 20.0 |
| Total | 89.0 | 125.0 | 139.0 | 70.0 | 609.0 |
拆得蛮散的,simplify有点庞大。
UML类图

3.2 应用对象创建模式
趁着这个小节,就把思路也记一下好了。程序主要分为以下几个部分:解析表达式(建立对象)、求导、(简化、)输出、判WF。总体来说,要比之前两次作业要“对象”得多,创建过程是工厂模式,只不过依然没有把工厂独立出类,而是统合在了Poly和Item类里。
我判断WF的思路是判错+判对,首先在main里排除非法字符、**和sin cos间空格等基础问题,再将字符串进行预处理后扔进Poly工厂。判对在Poly内递归进行,我首先将所有最外层括号连同里面的内容全部变为形如p1, s2, c3(分别代表表达式、sin、cos)一类表示,同时将其中内容存入一个list,数字就是对应角标。然后就可以开始递归构造表达式了,同时判断这一层的WF(如sin(sin(sin(x*x)))这种错误将在sin(x*x)这一层才报错)。然后先将表达式拆成项,每个项再分别再在Item工厂内构建(工厂同时接受刚才的list,以便递归构建表达式、sin、cos)。
其他的就没什么好说的了。
总体来说,有一定的抽象层次,但并没有抽离出来,还是不够“对象”,但已经有那么点味了。
3.3 BUG分析
本次中了十数刀,直接导致强测79,但其实都是优化错误。原因在于自己没有自测(面向样例和中测的DEBUG法)。
所以在修复的时候基本只改了一行,把输出化简结果改为输出求导结果。
具体而言,有以下几处:
- 无脑字符串去除同时的首位括号,没考虑配不配对,(...)+(...)这种就会GG
- sin(0)=0没问题,复制粘贴导致cos(0)也变成了0
- 表达式因子去括号没有考虑到sin, cos里面需要括号
3.4 心得与体会
德不配位必有灾。胡乱优化会翻下阴沟。
对魔力只有E的弓阶就别老想去扛魔法。
二、圣杯战争——互测阶段
如果说公测还可以自守一方清净地,那互测真的就是八方神仙各显神通了,我一个小萌新只好在大佬中间瑟瑟发抖捞一点hack分。基础的全地图无差别测评机就不说了,一群大佬仗着艺高胆大摆出了24小时全自动轰炸机,简直叫人手无缚鸡之力。
我不是大佬,所以我全是一个一个手动黑箱评测(第三次作业的时候写了个七人一起评的PY)。面向数据互测,不读别人代码(有几个强者的拜读了一下),直接怼自己觉得可能出错的点,虽然不如全自动机高端,好歹也有很强的针对性,倒也别有一番韵味。
1. 第一次作业
这一次作业比较简单,我一共hack到了两个点。没什么特别的针对性,就是把各种情况都试了一遍。如各种可省略输出、0、**0、前置0之类的。
- 将+-, -+处理成了+的错误
- 在输出形如-1*x时把-漏掉了(是的,我也曾犯过这错)
2. 第二次作业
在这一次互测中,我甚至没有下载别人的文件,纯属盲炸。数据构造仍然是各种情况、尽量复杂化,边界WF一类的。
事后,我观察到自己hack到了这些点:
- 错误理解”超过“,把边界判了WF
- cos(x), sin(x)带指数时求导错误
- cos(x)求导没带负号
看起来还是没什么参考价值。
3. 第三次作业
因为在强测中实在表现不佳,我所在的房间简直是血流成河。而在这时,我搭建起了无差别评测机,于是炸得越加爽快。
在这一场战斗中,我找到了所有人(包括自己)的BUG,并提交了hack7/7的数据上去找了找快感。这一次的BUG寻找战略依然是各种情况提交,不过这一次我也记录下了自己找到的所有BUG,以做统计(迫害)。
我大致找到了以下这些BUG:
-
优化翻车把+优化没了(x+x->11)
-
分析表达式时少读入项(x+x->1)
-
cos(0)=0
-
括号嵌套过多时TLE
-
左右括号错误
-
边界情况误WF(指数50)
-
sin内括号嵌套表达式误WF(sin(((cos(x))+(sin(x)))))
-
sin中的x**2被优化成x*x导致WF
-
在(前面加符号就会误判WF
-
对表达式开头的负号处理错误,比如-x-x会输出(0-(1-1))
-
……
似乎也没什么参考价值,不过告诉我们自测不到位,强测两行泪。
三、对比和心得体会
对比
难以望其项背,自己的问题蛮大的,说白了就是”对象“思想没有深入人心,面向过程的影子牵绊着我,对”抽象层次“的理解也不太到位。
心得体会
-
在头发乱飞之余甚至感受到了快感可能就是编程的乐趣吧
-
别乱优化,舍本逐末要不得
-
多自测多自测多自测
-
不要拖DDL不要拖DLL不要拖DDL
总体来说,我收获颇丰,希望自己在今后的单元里能改善问题,更抽象,更对象。

浙公网安备 33010602011771号