8.7 训练参考

本章是竞赛篇中的第一章节,例题难度和前7章相比有较大幅度的提升。如果希望在高水平算法竞赛中取得好成绩,本章中的所有例题(见表8-5)都是必须掌握的。另一方面,在初学阶段,不必强求掌握表8-5中带星号的例题,只需要尽量掌握未带星号的例题。

表8-5 例题列表

 

  类别     题号     题目名称(英文)     备注  
  例题8-1     UVa120     Stacks of Flapjacks     构造法;选择排序的思想  
  例题8-2     UVa1605     Building for UN     构造法;多种解法  
  例题8-3     UVa1152     4Values Whose Sum is Zero     中途相遇法  
  *  例题8-4   UVa11134     Fabled Rooks     问题分解  
  例题8-5     UVa11054     Wine trading in Gergovia     等价转换  
  *  例题8-6   UVa1606     Amphiphilic Carbon Molecules     极角扫描法  
  例题8-7     UVa11572     Unique snowflakes     滑动窗口  
  **  例题8-8   UVa1471     Defense Lines     使用数据结构加速算法  
  **  例题8-9   UVa1451     Average     数形结合  
  例题8-10     UVa714     Copying Books     二分法  
  例题8-11     UVa10954     Add All     Huffman编码  
  例题8-12     UVa12627     Erratic Expansion     递归  
  例题8-13     UVa11093     Just Finish it up     模拟法  
  *  例题8-14   UVa1607     Gates     二分法  
  例题8-15     UVa12174     Shuffle     滑动窗口或问题转换  
  *  例题8-16   UVa1608     Non-boring sequences     分治法;中途相遇法的思路  
  *  例题8-17   UVa1609     Foul Play     递归;构造法  
  *  例题8-18   UVa1442     Cave     扫描法  
  **  例题8-19   UVa12265     Selling Land     扫描法;状态组织;单调栈  

算法设计方法和技巧五花八门,因此本章的习题也比前7章更多。建议读者阅读所有题目,选择自己有思路的题目深入思考并编程实现。排列在前面的习题总体上会更简单一些,但也有一些例外。这些习题的整体难度比前7章大,读者需要做好花费更多时间的心理准备。

习题8-1 装箱(Bin Packing, SWERC 2005, UVa1149)

给定NN≤105)个物品的重量Li,背包的容量M,同时要求每个背包最多装两个物品。求至少要多少个背包才能装下所有的物品。

习题8-2 聚会游戏(Party Games, Mid-Atlantic 2012, UVa1610)

输入一个n(2≤n≤1000,n是偶数)个字符串的集合D,找一个长度最短的字符串(不一定在D中出现)S,使得D中恰好一半串小于等于S,另一半串大于S。如果有多解,输出字典序最小的解。例如,对于{JOSEPHINE, JERRY},输出JF;对于{FRED, FREDDIE},输出FRED。提示:本题看似简单,实际上暗藏陷阱,需要考虑细致、周全。

本题容易想复杂,或者把细节想错,强烈建议读者编程实现。

习题8-3 比特变换器(Bits Equalizer, SWERC 2012, UVa12545)

输入两个等长(长度不超过100)的串S和T,其中S包含字符0, 1, ?,但T只包含0和1。你的任务是用尽量少的步数把S变成T。每步有3种操作:把S中的0变成1;把S中的“?”变成0或者1;交换S中任意两个字符。例如,01??00经过3步可以变成001010(方法是先把两个问号变成1和0,再交换两个字符)。

习题8-4 奖品的价值(Erasing and Winning, UVa11491)

你是一个电视节目的获奖嘉宾。主持人在黑板上写出一个n位整数(不以0开头),邀请你删除其中的d个数字,剩下的整数便是你所得到的奖品的价值。当然,你希望这个奖品价值尽量大。1≤dn≤10 5

习题8-5 折纸痕(Paper Folding, UVa177)

你喜欢折纸吗?给你一张很大的纸,对折以后再对折,再对折……每次对折都是从右往左折,因此在折了很多次以后,原先的大纸会变成一个窄窄的纸条。现在把这个纸条沿着折纸的痕迹打开,每次都只打开“一半”,即把每个痕迹做成一个直角,那么从纸的一端沿着和纸面平行的方向看过去,会看到一个美妙的曲线。

例如,如果对折了4次,那么打开以后将看到如图8-30所示的曲线。注意,该曲线是不自交的,虽然有两个转折点重合。给出对折的次数,请编程绘出打开后生成的曲线。

图8-30 直角折痕

习题8-6 起重机(Crane, ACM/ICPC CERC 2013, UVa1611)

输入一个1~n(1≤n≤10000)的排列,用不超过96次操作把它变成升序。每次操作都可以选一个长度为偶数的连续区间,交换前一半和后一半。例如,输入5, 4, 6, 3, 2, 1,可以执行1, 2先变成4, 5, 6, 3, 2, 1,然后执行4, 5变成4, 5, 6, 2, 3, 1,然后执行5, 6变成4, 5, 6, 2, 1, 3,然后执行4, 5变成4, 5, 6, 1, 2, 3,最后执行操作1,6即可。

提示:2n次操作就足够了。

习题8-7 生成排列(Generating Permutations, UVa11925)

输入一个1~n(1≤n≤300)的排列,用不超过2n2次操作把它变成升序。操作只有两种:交换前两个元素(操作1);把第一个元素移动到最后(操作2)。

例如,输入排列为4, 2, 3, 1,一个合法操作序列为12122,具体步骤是:4231->2431->4312->3412->4123->1234。

习题8-8 猜名次(Guess, ACM/ICPC Beijing 2006, UVa1612)

nn≤16384)位选手参加编程比赛。比赛有3道题目,每个选手的每道题目都有一个评测之前的预得分(这个分数和选手提交程序的时间相关,提交得越早,预得分越大)。接下来是系统测试。如果某道题目未通过测试,则该题的实际得分为0分,否则得分等于预得分。得分相同的选手,ID小的排在前面。

问是否能给出所有3n个得分以及最后的实际名次。如果可能,输出最后一名的最高可能得分。每个预得分均为小于1000的非负整数,最多保留两位小数。

习题8-9 K度图的着色(K-Graph Oddity, ACM/ICPC NEERC 2010, UVa1613)

输入一个n(3≤n≤9999)个点m条边(2≤m≤100000)的连通图,n保证为奇数。设k为最小的奇数,使得每个点的度数不超过k,你的任务是把图中的结点涂上颜色1~k,使得相邻结点的颜色不同。多解时输出任意解。输入保证有解。如图8-31所示,k=3。

图8-31 连通图

习题8-10 奇怪的股市(Hell on the Markets,ACM/ICPC NEERC 2008, UVa1614)

输入一个长度为nn≤100000)的序列a,满足1≤ai≤i,要求确定每个数的正负号,使得所有数的总和为0。例如a={1, 2, 3, 4},则设4个数的符号分别是1, -1, -1, 1即可(1-2-3+4=0),但如果a={1, 2, 3, 3},则无解(输出No)。

习题8-11 高速公路(Highway, ACM/ICPC SEERC 2005, UVa1615)

给定平面上nn≤105)个点和一个值D,要求在x轴上选出尽量少的点,使得对于给定的每个点,都有一个选出的点离它的欧几里德距离不超过D

习题8-12 顾客是上帝(Keep the Customer Satisfied, ACM/ICPC SWERC 2005, UVa1153)

nn≤800000)个工作,已知每个工作需要的时间qi和截止时间di(必须在此之前完成),最多能完成多少个工作?工作只能串行完成。第一项任务开始的时间不早于时刻0。

习题8-13 外星人聚会(Meeting with Aliens, UVa10570)

输入1~n的一个排列(3≤n≤500),每次可以交换两个整数。用最少的交换次数把排列变成1~n的一个环状排列。

习题8-14 商队抢劫者(Caravan Robbers, ACM/ICPC NEERC 2012, UVa1616)

输入n条线段,把每条线段变成原线段的一条子线段,使得改变之后所有线段等长且不相交(但是端点可以重合)。输出最大长度(用分数表示)。例如,有3条线段[2,6],[1,4],[8,12],则最优方案是分别变成[3.5,6],[1,3.5],[8,10.5],输出5/2。

习题8-15 笔记本(Laptop, ACM/ICPC Daejeon 2012, UVa1617)

n(1≤n≤100000)条长度为1的线段,确定它们的起点(必须是整数),使得第i条线段在[ri,di]之间(0≤ridi≤1000000)。输入保证rirj,当且仅当didj,且保证有解。输出“空隙”数目的最小值。如图8-32所示,5条线段的范围分别为[4,8],[1,3],[8,10],[0,3],[6,8],一组解如图8-32所示,空隙有3个。

图8-32 5条线段范围

最优解如图8-33所示,空隙数目仅为1(T2T5之间)。

图8-33 最优解

习题8-16 弱键(Weak Key, ACM/ICPC Seoul 2004, UVa1618)

给出k(4≤k≤5000)个互不相同的整数组成的序列Ni,判断是否存在4个整数NpNqNrNs(1≤pqrsk),使得NqNsNpNr或者NqNsNpNr

习题8-17 最短子序列(Smallest Sub-Array, UVa11536)

nn≤106)个0~m-1(m≤1000)的整数组成一个序列。输入kk≤100),你的任务是找一个尽量短的连续子序列(xa, xa+1, xa+2,…, xb-1, xb),使得该子序列包含1~k的所有整数。

例如,n=20,m=12,k=4,序列为1 (2 3 7 1 12 9 11 9 6 3 7 5 4) 5 3 1 10 3 3,括号内部分是最优解。如果不存在满足条件的连续子序列,输出sequence nai。

习题8-18 感觉不错(Feel Good, ACM/ICPC NEERC 2005, UVa1619)

给出一个长度为nn≤100000)的正整数序列ai,求出一段连续子序列al,…,ar, 使得(al+…+ar)*min{al,…,ar}尽量大。

习题8-19 球场(Cricket Field, ACM/ICPC NEERC 2002, UVa 1312)

一个W*H(1≤W,H≤10000)网格里有n(0≤n≤100)棵树,如图8-34所示,要求找一个最大空正方形。

图8-34 球场

习题8-20 懒惰的苏珊(Lazy Susan, ACM/ICPC Danang 2007, UVa1620)

把1~nn≤500)放到一个圆盘里,每个数恰好出现一次。每次可以选4个连续的数字翻转顺序。问:是否能变成1, 2, 3,…, n的顺序?

提示:需要先奇偶分析排除无解的情况,然后写程序、找规律,或者手算得出有解时的构造算法。

习题8-21 跳来跳去(Jumping Around, ACM/ICPC NEERC 2012, UVa1621)

你的任务是数轴上的0点出发,访问0, 1, 2,…, n各一次,在任意点终止。需要用票才能从一个点到达另一个点。有3种票,跳跃长度为1, 2, 3,分别有a, b, c张(3≤a,b,c≤5000),且n=abc。每张票只能用一次。输入保证有解。

例如,a=3,b=4,c=3,则n=10,一种可能解为0->3->1->2->5->4->6->9->7->8->10,其中第1种票的3张分别用在1->2,5->4,7->8;第2种票的4张分别用在3->1,4->6,9->7,8->10;第3种票的3张分别用在0->3,2->5,6->9。

习题8-22 机器人(Robot, ACM/ICPC Beijing 2006, UVa1622)

有一个n*m(1≤nm≤105)的网格,每个格子里都有一个机器人。每次可以发出如下4种指令之一:NORTH、SOUTH、EAST、WEST,作用是让所有机器人往相应方向走一格。如果一个机器人在执行某一命令后走出了网格,则它会立即炸毁。

给出4种指令的总条数(0≤CN,CS,CW,CE≤105),求一种指令顺序使得所有机器人执行的命令条数之和最大。炸毁的机器人不再执行命令。

习题8-23 神龙喝水(Enter the Dragon, ACM/ICPC CERC 2010, UVa1623)

某城市里有n个湖,每个湖都装满了水。天气预报显示不久的将来会有暴雨。具体来说,在接下来的m天内,每天要么不下雨,要么恰好往一个湖里下暴雨。如果这个湖里已经装满了水,将会引发水灾。为了避免水灾,市长请来一只神龙,可以在每个不下雨的天里喝干一个湖里的水(也可以不喝)。如果以后再往这个干枯的湖里下暴雨,湖会重新被填满,但不会引发水灾。神龙应当如何喝水才能避免水灾?n≤106m≤106

提示:需要优化算法的时间复杂度。

习题8-24 龙头滴水(Faucet Flow, UVa10366)

   

图8-35 龙头滴水示意图

x=0的正上方有一个水龙头,以每秒1单位体积的速度往下滴水。x=-1, -3,…, leftxx=1, 3, 5,…, rightx处各有一个挡板,高度已知。求经过多长时间以后水会流出最左边的挡板或者最右边的挡板。如图8-35所示,leftx=-3,rightx=3,4个挡板高度分别为4, 3, 2, 1,则6秒钟之后水会从最右边的挡板溢出。

输入第一行为两个奇数leftx,rightx(leftx≤-1,rightx≥1),接下来的各个正整数表示从左到右各个挡板的高度。挡板个数不超过1000。

习题8-25 有向图D和E(From D to E and back, UVa11175)

给一个n个结点的有向图D,可以构造一个图E:D的每条边对应E的一个结点(例如,若D有一条边uv,则E有个结点的名字叫uv),对于D的两条边uv和vw,E中的两个结点uv和vw之间连一条有向边。E中不包含其他边。

输入一个m个结点k条边的图E(0≤m≤300),判断是否存在对应的图D。E中各个结点的编号为0~m-1。

提示:虽然题目中m≤300,实际上可以解决的规模远超过这个限制的问题。

习题8-26 找黑圆(Finding [B]lack Circles, Rujia Liu's Present 6, UVa12559)

输入一个h*w的黑白图像(30≤wh≤100),你的任务是找出图像中的圆。每个像素都是1*1的正方形,左上角像素的中心坐标为(0,0),右下角像素的中心坐标为(w-1,h-1)。对于一个圆,它的圆周穿过(只是接触到像素边界不算)的像素都会被涂黑(用1表示)。没有被任何圆穿过的像素仍然是白色(用0表示)。圆心保证在整点处,半径保证是1~5之间的整数。最多有2%的黑点会变成白点。

提示:方法有多种,尽情发挥创造力吧。

习题8-27 海盗的宝箱(Pirate Chest, ACM/ICPC World Finals 2013, UVa1580)

有一个顶面为m*n的池塘,已知每个格子(i,j)的水深d(i,j)(1≤im,1≤jn,0≤d(i,j)≤109)。要求放一个长和宽分别不超过ab(但长宽可以交换,高度任意)、体积尽量大的长方体,使得长方体的顶面严格位于水平面之下。注意,池塘里放入长方体后,水面会上升(即使长方体紧紧贴住墙壁)。池塘四周是足够高的墙壁。

如图8-36(b)中放了一个底面为1*3,高度为1的长方体,体积为3;图8-36(c)中放了一个1*2*2的长方体,体积为4。输入保证a*b不足以覆盖整个池塘。1≤a,b,m,n≤500。

 

              
   (a)       (b)       (c)   

图8-36 水池示意图

习题8-28 打结(Knots, ACM/ICPC ACM/ICPC Jakarta 2012, UVa1624)

有一个圆形的橡皮圈,可以对它进行Self loop和Passing两种操作,如图8-37所示。

图8-37 Self loop和Passing操作

输入一个橡皮圈,判断是否可以由原始的圆形橡皮圈经过重复的两种操作得到。橡皮圈的描述方法如下:首先是两个正整数LPL≤106P≤5000),然后把橡皮圈上的L个位置按顺序编号为0~L-1,接下来是P(1≤P≤5000)个整数对(Ai,Bi),表示从上往下俯视时位置Ai挡住位置Bi(0≤Ai,BiL)。输入保证0~L-1中的每个位置最多在一个数对中出现。

如图8-38所示,图8-38(a)和图8-38(b)都可以由原始橡皮圈得到,但图8-38(c)不可以。其中图8-38(a)的L=20,P=5,5个数对分别是(0,8),(2,10),(4,12),(15,5),(18,7)。

 

              
   (a)       (b)       (c)   

图8-38 橡皮圈效果

提示:本题不需要特别的数学知识或算法知识,但需要仔细思考。

————————————————————

(1) 如果没有公证人,你可以不动声色地换一个数。

(2) 另外,本题还有一些小技巧简化代码,建议读者参考代码仓库。

(3) A[1…P-1]表示子序列A[1],A[2],…,A[P-1]。

(4) 因为要求字典序最小解,输出时还有一个贪心过程,详见代码仓库。

(5) A[1…P-1]表示子序列A[1],A[2],…,A[P-1]。