分类目录归档:acm

[POJ 3422]

Kaka’s Matrix Travels

费用流。

好久没写网络流的题目了,敲了很久,不过还是1A了。

这题和以前qoshi推荐的DP是同类题目,但这超过了DP能求解的规模,所以只能用费用流来做了。思路是把矩阵每个元素拆点为ui和vi,并根据费用流算法的需要进行建图。然后重复k次增广操作即可。增广用的是基于栈的spfa。g++下跑了938ms。

[POJ 3150]

Cellular Automaton

矩阵运算。

题意抽象出来,即是求A^k*x(mod m),其中A是n*n的循环矩阵,x是n维列向量。

很直接的思路是O(n^3*lgk),但这里n最大500,TLE的。如果利用A是循环矩阵的性质,那么其实每次只要计算第一行就可以了,其他行都可以由第一行移位得到。这样就可以O(n^2*lgk),实现出来最快500ms。

看评论还有一种O(n*lgn*lgk)的算法……但是想了一早上也没明白怎么弄,饿得不行吃饭先了……

[POJ 3159]

Candies

差分约束系统。

偶尔发现的很好的题目,对最短路径算法的优化要求较高。

敲了一个SPFA+SLF。其中双端循环队列是手写的,int读入用了getchar处理以节省时间,作了去重边处理。但即使这样也才250ms(g++)。

之后又考虑了用dijkstra。没有优化过直接交果然TLE了。然后开始考虑改进。直接用最小堆来实现最优的dijkstra不太好写,而折中地每次将可能更新最短路径值的点全部push进优先队列的做法是相对比较好实现的,也不会耗损太多时间。第一次写这样的dijkstra,调试了挺久。最后在g++下235ms,c++下1297ms。

吐个小槽……priority_queue里面自定义仿函数时,若比较用的是<,建出来的竟然是大根堆……直觉上怎样也觉得<对应的应该是最小元素在上的小根堆才对……>__< 后记:第二天过来后被Usozki教育了下,他的代码仅仅是SPFA+栈,没有太多优化……但是直接跑出79ms进入第一版了…… 附POJ 3159 by Usozki:

[POJ 3101]

Astronomy

分类里写的是扩展欧几里德,但完全用不到。倒是被高精度稍微卡了下。

题意是共有n个星体各以vi的速度绕同一中心公转,问所有星体排成一条直线的周期。

这里注意“排成一条直线”,可以是在圆周的一侧或是另一侧。这里可以取速度最快的星作为运动参照物,求其他星体相对该星的速度,并计算各星体(v0-vi)*x可同时被0.5除尽的最小倍数值x。x即为所求周期值。0.5是因为可在圆周的任意一侧。

用题意vi = 1/ti来表示的话,则1/t0 – 1/ti = (ti-t0) / (t0*ti),那么取所有分母的lcm为nu,所有分子的gcd为de,则nu/(2*de)则是所求的x了。

思路出来之后,还有部分细节,首先就是去重,然后是计算素数表大小和估计高精度数组最大长度,最后每次求出某分数值时要约分到最简。这里所谓的“高精度”比较有意思的是,用质因数分解的方式保存各个值,这样可非常简便地求gcd和lcm。

Google Round A China New Grad Test 2014

早上做了一场Google的在线笔试

赛制都很熟悉了,和之前的GCJ一样的。比赛时长3小时,共5题,每题都分small和large两组数据。

Problem A. Read Phone Number

读入两个字符串,根据第二个串给出的分段方式,对第一个串进行分析并输出结果。

写第二个串的读入那部分时卡了很久很久。真是对字符串处理太不熟练了,之前北大校赛的时候也是卡很久在字符串处理上。最后还是借鉴了之前用getchar()代替scanf(“%d”,&d)来读入整数以节省时间的方式来读入了每个串分段长度值。提交大数据时一直报含有非ascii字符,结果发现自己数组越界了,如果不是提示这里也就WA掉了。这题做完时已经整整41分钟了。

Problem C. Sorting

随后很自然的看了下board,看到C题过的人很多。点开发现是大水题,两次排序后重构数组输出即可。

Problem B. Rational Number Tree

C题过了后,心态稳下来了。开始读B,发现也是只需要在树上寻根即可,非常简单的处理。大数据提交前看了眼输出,发现竟然有负数。分析到long long最多是2^63-1,遂改成unsigned long long提交。

Problem D. Cross the maze

到这时候已经完全进入状态了。机器人走迷宫的题目,读完后发现也不需要太复杂的处理。分析完之后可以发现,机器人每一步的走法是确定的,而所需要做的就是模拟它走完10000步,看是否经过终点。这里处理写得很凌乱,因为当时以为只有两个小时敲得比较仓促。但提交完发现竟然还有1小时。。。

Problem E. Spaceship Defence

最后一题了,这是唯一稍微考虑了下复杂度的问题。这里大数据是100个源点,图有80000个点,若是稠图最坏情况O(M*N^2)是会TLE的。过了小数据后想了很久怎么对问题进行抽象,但始终没有太好思路。这个时候时间也不多了,想想大数据有8min时限,下下来碰碰运气好了。结果SPFA没有任何优化,1分钟不到就跑出结果了,遂提交之。

12点封榜的时候,好像是排50名左右吧。。。Arios比我快2分钟,能离伟神这么近我也很满足了。睡过午觉过来一看,发现自己AK了。。。。。。最后排名29。其实题目不难的,但貌似很多ACM神牛都没有来玩,不知为何了。。。

最后的board

事后马上收到了Google的邮件,恭喜通过笔试云云。

不禁也在问自己,这个时候如果要选择,是继续读完研究生,还是去Google工作?

心里面作出回答只用了10秒。而且非常清楚,自己这一决定,怎样也不后悔。

祝自己好运吧。

[POJ 2065] & [POJ 1166]

SETI

The Clocks

两题都是高斯消元法。(也都1A了^^)

两题题面都很有意思,分别描述了确定有唯一解的模运算线性方程组,唯一解是因为前者是范德蒙行列式,后者则是给定了满秩系数矩阵。

两题都没有太大难度的,代码也相近。

2065的:

1166的:

好久没来了……这几天都在看书+帮人折腾VPS。Linode用久了就以为主机商都该是这样的,现在算认识到很多产品还是良萎不齐的(而且还死贵……)

[POJ 3020]

Antenna Placement

二分图匹配。

其实是很久以前做的题目了。今天被Usozki问了下这题怎么做,看了他的代码,感觉值得改进的地方不少……便自己着手重做了下这题,希望能讲清边表的写法。由于之前hackerhank出过一题很刁钻的匈牙利,觉得已经把这个算法弄得很透彻了(包括递归改非递归、每轮匈牙利时局部链表指针改全局、每次不重新memste标记数组等等),但这次重写这题还是用了很久。

这里用了一个题目的特点(可以染色成国际象棋棋盘那样的二分图),使得每个匹配的共算了两次;又或者其实可以每次仅从一种颜色的点出发,这样就只算一次匹配。

这是今天写的代码:

这里建图是先编号,再检查上方和左方是否存在点,然后加边的。代码里函数功能应该都区分得很明显了。这样写出来的边表,是做很多图论题时必须使用的数据结构(甚至其他类型题目里也经常用到)。无论是时间、空间,还是代码实现难度方面都是很好的。

另外也贴下以前写的,当时不会用边表,但是代码还算是比较齐整了:

[POJ 1487]

Single-Player Games

还是高斯消元法。

这题的特点是输入是用树来表示的,并且需要做类似编译原理那样的词法和语法分析。处理字符的时候小心一点,问题不会太大(但还是被负数的’-‘阴到了。。)。用递归来表示每个括号的匹配情况,符号移到等式右端(取负),数值直接累加,递归返回时每个值除去子树规模再累加到父节点数组上即可。由于输入规模不大,除了字符串处理也没有其他麻烦了。

解线性方程组的时候,注意每个方程已经指定了主元了,如果系数为0即对应变量无解,所有依赖于该变量的其他变量也无解。但其他剩余有解的变量还是要解出来的。这题比之前那题取模的要好处理,方程比较整齐,而且可以直接用浮点数。

另外这题也是我在POJ上有记录的第200题,貌似里面夹杂的水题不少。。。但还是值得纪念:

296_0

[POJ 2947]

Widget Factory

高斯消元法。

其实就是线性代数里解线性方程组,但这题还要求等式两边mod7。

解向量中xi的取值范围是[3,9],共有m个方程,判断是否有解,如果有解,要判断是否有唯一解。

这题一开始走了弯路,想象以前解普通线性方程组那样用浮点数依次选列主元后化成上三角来求解。但发现在这题mod7条件下,行不通。

后来发现可以用一个很差的时间复杂度完全使用整数进行处理。。。由于数据规模不大,发现这样是可行的。每次消元处理后都也要注意各种取模,不然很易RE。

反正最后就是各种暴力。。。就过了。。。

[POJ 2348]

Euclid’s Game

博弈问题。

输入是两个数A、B(设A>=B),有两个人轮流操作,每轮可以从A中减去B*k,k满足A>=B*k,随后令A’=A-B*k,A=max(A’,B),B=min(A’,B),再进行下一轮。先使得B==0的人获胜。

分析题意易得,A、B两数的组合每次的mxk=A/B值决定了当前选手是否拥有主动权:若mxk>1,那么自己可以选择(mxk-1),对手只能选1,下一轮依然自己先选,若下一轮mxk==1还可以本轮自己全取,依然是主动;但若mxk==1,那么自己这轮就无法选择了。由于这里每轮都是最优操作,那么首先获得主动权的人可以赢得比赛。由此迭代更新A、B,并找到首先不为1的A/B值,此轮的先手就是赢家。

另外,最后一组A、B的值无关紧要,因为此时无论谁先手,都必定全取k=A/B。