首先对F题出了陈题表示万分抱歉,我们都没注意到在2009哈尔滨赛区曾出过一模一样的题。其他的话,这套题还是非常不错的,除C之外的9道题都有队伍AC,最终冠军7题,与我们的预期非常接近。
Problem A: Alice and Bob 出题人:章雍哲
(特别感谢Evolution队对该题解法的贡献)
这道题正规的做法需要讨论各种情况:
1) 没有1的情形,很显然,只需讨论(sum+n)的奇偶性
2) 全1的情形,对1的数量模3进行讨论
3) 非全1的情形,记1的数量为n1,其他为n2
a) 若有偶数个1,讨论(sum+n2)的奇偶性。
b) 若有奇数个1,先手必胜,因为必可以转化成a)或1)的必败态
c) 一个2带若干个1:这是本题的一个大trick,它的特殊性是可以直接转化为全1的情形,因此需要枚举一下当前的决策。
以上讨论忽略了不少细节,即每种情形下的必胜策略是什么,留给大家自己思考吧。
另一种做法:
其实比较容易猜到,大的数只和奇偶有关。于是按下列方法记状态dp即可AC:
Dp[1的数量][2的数量][3的数量][4的数量]
其中大于4的数按奇偶归类为3和4。
应该有不少队伍把4也归类为2去dp,这样是错的,因为在极端情况下,2和4并不等价,即上面提到的trick。这个trick其实给在样例里了。
Problem B: Break the Chocolate 出题人:曹雪智
第一问,一次掰一块巧克力,答案是a*b*c-1,因为每掰一次都让巧克力块数+1
第二问,以2为底取上整的[loga]+ [logb]+ [logc]。可以这么想:你把巧克力一切两半,把小的那块直接丢掉,只切大的。因为你用最少步数切掉大的那块时,把小的那块一按同样方式一并切也一定能切碎。这样对每个维度对半切一定是最优的方案。
Problem C: Construct the Great Wall 出题人:章雍哲
连通性状态压缩动态规划。
我们来把题意做个转换:N*M的网格中,有一些必须取的格子,一些不能取的格子。最后你要取一些格子,它们构成一个连通块,且不含空洞,求周长最小是多少。这里空洞表示了连通块的边界由不止一个简单多边形构成,是非法的。
一看就是个经典的状压dp,每行是用最小表示记的状态,按格转移。状态中包含:
1) 与边界连通的没有选的格子
2) 已选的格子(要最小表示记连通性)
3) 不与边界连通的没有选的格子(要最小表示记连通性),因为要防止空洞的出现
代码量应该要上200行,在可做题甚多的情况下应该没有队伍会去写吧。
P.S.据说中山大学Metalgarurumon最后在写C,差点写完,要orz一个。
Problem D: Disney’s FastPass 出题人:---
简单的状态压缩dp,每个必去的景点记0,1,2状态,分别表示已经游览过、没游览过但有票、没游览过且没票。dp的状态是dp[当前在哪个点][3^k每个景点状态],沿着图上的边转移。一个点上可能有很多个景点,可以2^k转移,也可以每个点给自己连一条长度为0的边,然后一个一个转移下去。转移有环,需要用SPFA或者其他快速的最短路径算法来实现。
这题时限比较宽,用4^k表示每个景点状态似乎也能过。
Problem E: Eliminate the Conflict 出题人:---
可以转化为2-SAT问题求解
Alice每一轮的出法只有两种,这样建出了2*n个点,每一轮的两种出法只能二选一。而每一个规则可以在图上建立一些有向边,具体:建a->b的语义是如果a代表的节点被选,那么b节点也必须选。
建了图之后,求强连通分量,如果某一轮对应的两点在同一个强连通分量里,就不合法,否则一定能找出一种方案。
Problem F: Fruit Ninja 出题人:谭天
这题O(n^3)的做法很好想,枚举两圆求所有切线,拿切线O(n)check与多少圆相交。看了数据范围就应该明白,这种做法不能过这道题。
O(n^2logn)的做法就是先枚举一个圆,然后想象一条切线绕着它的圆周在转,扫过其他圆。其他每个圆在这条切线转动的过程中,会形成1-2个区间,当切线在该角度区间中是会穿过这个圆的。求出这些区间,排序+统计即可。
F题有个小trick,就是多个圆嵌套的情况。解决方法也很简单,枚举中心的圆的时候,先处理掉被它包含和它包含的圆,剩下的圆就正常做了。
数据用三个不同的代码对拍过,应该不会有精度问题。
另:
这道题我们暑假里就有了,当时谭天在百度之星无聊时YY了这个题,后来和我们讨论时,我想到以前割过CERC的某题,给一些点,求用一个给定半径R的圆最多能覆盖多少,做法是枚举点,让圆绕着点转,算其他点被圆覆盖的角度区间。于是联想到这题可以让切线绕着圆转,对其他圆也算出这么一个区间,然后排序统计就出来了。
我们其实也担心过,这么个感觉很经典的问题会不会哪里出出来过,后来只在Ural上找到一道用直线切点的题,做法也是让直线绕点转。我们想想只要不是原题就可以了,思路这个东西么,都是举一反三的,于是就把这题出在成都了。
今天在人人上看到ACMICPC主页君的状态,感觉太瞎了……交大在2009-2010赛季没有去哈尔滨,之后队内也从没拿那套题做过训练,于是导致了这样一个失误。
Problem G: GRE words 出题人:郭晓旭
建立所有单词的AC自动机,对于每个节点的转移,都是从parent[]或者从fail[],fail[fail[]],...得到的。可以看出fail[]的关系形成一棵树,于是问题转化成,不断在节点处插入,询问点到根路径上的最大值,可以利用dfs序列转化用线段树维护。
瞿钧提供了另外一个算法:
将所有单词连起来,做后缀数组,然后从后往前扫描每个串,找出它在SA数组中与它前缀相同的一个区间,对这个区间取max值+1。这个串做完后,再对SA数组中该串出现过的所有位置更新一下。用线段树能够O(logL)的时间找出区间边界、求区间最大值、更新。
总时间复杂度O(LlogL)。写了一个,比自动机做法略慢。
Problem H: Holiday’s accommodation 出题人:胡张广达
这道题前期就有大片队伍过了,有些出乎出题人的意料。我们原本的定位是一道需要动动脑子的中期题。
我们把每个点到另一个点的映射a->b看做是树上的一条路径。
首先有个显而易见的结论:这n条路径任意两条都相交(否则可证明不最优)。这个结论可以继续推广为:这n条路径都会交与某个点,这样我们找出这个点,然后将它与其他点的路径长度求和,乘2后输出即可。证明留给读者。
而仅仅用“任意两条路径都相交”其实就可以推出答案。枚举每条边e,这条边将树分割成A和B两个子树,那么这条边一共出现在2*min{|V(A)|,|V(B)|}的路径上。假设|V(A)|<=|V(B)|,考虑点数较小的那棵子树A,其中不可能存在一条不经过e的路径,否则,此时的B中一定也存在一条不经过e的路径,那么这两条路径不相交,显然不是最优。而2*min{|V(A)|,|V(B)|}容易证明是一个上界。
Problem I: Isabella’s message 出题人:章雍哲
除了题目描述比较长之外,本质就是一个水模拟。
Problem J: Ji-Tu Problem 出题人:章雍哲
(感谢各种人写标程,做数据@谭天@曹雪智@商静波@缪沛晗)
这道题是个可做题,细节很多,需要很细致的讨论。赞南京大学Heracles队,全场唯一的AC。
题解好难写@.@,等我之后update吧~~
这里给几个tricky的数据(当然trick还不止这些),大家可以先看看是自己否漏考虑了情况。
3 2
60 30 15 (多解)
3 2
44 22 11 (唯一)
5 1
16 11 (唯一)
据现场回来的judge说,有些队就错了要判素数的点,有些可惜啊。
最后,代表出题组:
感谢Seraphim为我们检验算法和数据
感谢不少已退役的学长为我们修改题面,提出宝贵意见
感谢刘思壮为我们提供了一个漂亮的tex模板
感谢参与验题赛的队伍和同学Epic,Evolution,Hurricane,任春旭
感谢俞勇教练,感谢ACM竞赛组委会,给我们一次激动人心的出题机会
感谢国家
原文地址