开始做狗狗40题,不知道在毕业前能不能做完。
第一题The Willy Memorial Program就虐死我了,恶心的模拟……
数据范围超小,于是开始乱搞……我的思路是用水将能填满的水管都填满,填满的步骤是根据水位来进行的(每升高单位水位算一个步骤),于是每个步骤可以分为以下几个小步骤:1~判断当前共有几个水管是一起升高水位的(程序中用n表示),那个该步骤就加入n个单位水位,使得这些水管中每个水管的水位上升一单位;2~判断当前有无可能达到目标水位线;3~若达到目标水位线,判断是否已溢出(虽然在程序中认为水管有盖,但是题目中水管是没有盖的,所以要加入这个判断,这个判断比较简单,写个循环判断水位线是否达到了已存在的水管中y值在最低——或者说y值在最大——位置的水管盖子),若没有则进入下一步。最后,若所有水管已填满但还没有达到指定水位线则算溢出情况。
因为实际目标比实际目标水位线稍微高一点,如果到达水位线后直接进行判断有点繁琐(考虑到连接其他的水管,题目中也已提到),所以我用这一步的下一步进行判断,下一步若淹过目标水位线,则前一步就是答案,只需要这一步的总体积减去这一步所用的体积(程序中的v-n)即为答案。
当然,之前需要先预处理一下水管之间的连接情况(储存在程序中的pc)。在判断连接水管时用vector储存(我是用vector来实现BFS的)。
注意:有数据是指定水位线并不在水管内部(尤其是在水管下方,已经超出水管范围的位置,这里我WA了不知道多多少次才发现)。
参考程序如下。
#include
#include
#include
第二题Farmland搞定。
我的思路是去找逆时针旋转,定下某个顶点时,角度改变最大的那个点(第三个点),这里共涉及两条边,还未超过该点时的一条边(该点与该点之前的点组成的边),以及超过该点时的一条边(该点与该点之后的点组成的边),以该点位旋转点时,前一条边经过最大的角度(逆时针旋转)达到另一条边。按照这个思路,当完成点与点相邻情况的储存后(邻接表),定下前两个点(该点前一个点和该点)就可以确定第三个点(该点之后的点),以上“该点”在程序中设为o点(因为两条边是通过该点旋转的,有中心的意思),接着设该o点之前点为m点,那么可以唯一确定第三个点设为n点,于是用一个next函数储存,即next[m][o]=n(m与o不相邻时,next值为-1)。
实际上以上的程序还有一个问题,这是在我一开始没有想到的,也为此WA了很多次,就是这样用next函数确定多边形,有两种情况:一种是题目所要求的多边形(内部没有杂点杂边,不然在题设图是connected的情况下,选择点和边时会选中里面的点和边,原因就是选择这些点和边会比外面的点和边旋转角度更大),此时,这个多边形是正方向的(对于内部来说),且是逆时针的;另一种则是当整个图的外部没有杂点和杂边的时候,有可能会产生这个图的最外部的多边形(实际上,若把无穷大点也作为一个有意义的点的时候,这种多边形也是满足题意的,因为这个多边形的方向对于外部区域来说是正方向的,虽然它本身是顺时针的,此时这个多边形的内部就是整个图的外部,这种思想在复变函数中很常见,比如求一个复变函数的回路积分的时候,当这个复变函数只有有限个孤立奇点,且孤立奇点都在回路内部,那么就可以用无穷大点——也是一个孤立奇点——的留数来计算,此时的正方向就是顺时针而非逆时针)。解决的方法是多一个多边形是逆时针还是顺时针的判断:在平面中任取一点(一般为原点),按照点的顺序,求每两个相邻的点的cross product(严格地来说,是这两点与原点组成的两个向量的cross product),想加后求出来的是这个多边形的面积(的两倍),当然,这个面积是带方向的,正为逆时针,负为顺时针,证明略麻烦,以后有时间了再把严格的证明放上来。
具体在实施,判断旋转角度的时候我用的是cross product和inner product共同判断的方法(前者主要判断正负来决定位置,后者在决定了位置后决定其角度的大小,注意前者因为只需要正负所以不需要单位化,但后者需要用大小所以需要单位化处理,这里我也WA了几次)。
另外,求出的答案需要除以size,因为从满足条件的多边形上的每个点出发都可以得到同一多边形。
具体的代码如下。
#include
#include
#include
第三题Transmitters搞定!
1A搞定,这题原来我两年前做过,当时用的还是C,估计是为了凑齐当时选入集训队的99分……这题比起上两题来说不知道要人性化多少,用一个cross product判断以r为中心的两个点(有顺序)的逆时针角度是否超过pi就行,复杂度O(n^2)即可过(n=150的数据量实在是很小,0msAC)。
#include
#include
#include
结束了答辩(好吧,我貌似还要二辩),继续gougou40的节奏。
Split Windows是一道巨恶心的模拟题(虽然目测后面还有更多更恶心的模拟题),本来打算用链表写树,后来觉得没这个必要,还是用数组写了。
我的思路用了两次递归,第一次是计算总window的width&height,第二次是根据父节点的width&height推子节点的width&height,同时画出此split时window的形状。一开始觉得好难画,后来想了一下,递归的时候把某时刻的LRUD(左右上下,也就是子window的框架)全部记录,并递归下去的话,还是比较容易画的。具体画法是:首先画出window的轮廓(初始化),每分割一次就画分割线(注意当'-'和'|'遇到时要变成'*'),最后递归到字母时,直接在左上角将本来的字符用字母覆盖即可。
数据应该不是太强,而且样例也给的也应该是数据里面比较强的了,所以只要能写出一般就不会WA(不过因为一开始window的初始化错误,我还是WA了3次,太弱了……)。
#include
#include
#include
gougou第一部分结束(打算每部分4题,也不知道自己能坚持几个部分……)。