NOIP2013题目简析

chunlvxiong的博客


 

DAY1:

T1:转圈游戏

  可以发现答案为[x+m*(10^k)]%n。

  瓶颈在于k最大10^9,用快速幂轻松解决。

T2:火柴排队

  容易发现,当最小的ai对应最小的bi,第二小的ai对应第二小的bi,……时两列火柴之间距离最小。

  然后你发现可以一个序列不动,只移动另一个序列(两个序列都移动的最少步数是一样的)。

  然后你发现ai的大小没有用,只有排序后的编号才有用,b数组同理。

  举个例子说明吧:

  排序后的a数组编号:2 3 1 5 4

  排序后的b数组编号:1 4 2 5 3

  答案就是1 4 2 5 3-->2 3 1 5 4的代价。

  把2 3 1 5 4视为1 2 3 4 5,那么1 4 2 5 3就是3 5 1 4 2。

  也就是3 5 1 4 2-->1 2 3 4 5的代价。

  由于1 2 3 4 5没有逆序对,那么答案就是3 5 1 4 2的逆序对数(因为你每次调整可以减少一个逆序对)。

T3:货车运输

  首先容易发现开车经过的路多不是件好事情。

  很多路实际上根本不会走。哪些路会保留呢?

  答案:最大生成树(这题可能是森林)中的边才会保留。(这一步很机智)

  道理很显然,如果你可以用大的边走到一个城市,为什么要走小的边呢?

  所以你先kruskal跑一遍最大生成树,这样图就变成了一颗树(或是森林)。

  如果询问的两个节点不在一棵树里,那么显然答案是-1。

  否则你可以参考倍增LCA的做法,仍然用倍增思想,只不过维护的是min值。

  这样这个问题就解决了。

 

DAY2:

T1:积木大赛

  这个问题其实不难。

  首先你发现一次操作的区间长度越长越好。

  如果a[i]<a[i-1],那么当a[i-1]变为0的时候,a[i]也肯定为0了,不需要额外的操作步骤,否则需要多a[i]-a[i-1]步骤。

  复杂度O(N)。

T2:花匠

  我的做法实现起来很烦,但是思维难度几乎没有。

  因为有两种不同的方式,你肯定要分开处理。

  只考虑第一种,即2i-1<2i>2i+1的形式,另一种是同理的。

  因为你发现实际上是一高一低的过去的,考虑dp,用dp[i][0]表示它作为高的那个最大的摆放数,dp[i][1]表示它作为矮的那个的最大的摆放数。

  每个数dp[i][1]=1

  dp[i][0]=max(dp[j][1])+1(需要满足h[j]<h[i])

  dp[i][1]=max(dp[j][0])+1(需要满足h[j]>h[i])

  朴素的转移是O(N^2)的,所以会T掉。那么你考虑开一颗线段树按照h值维护,然后你可以在O(NlogN)的时间内完成DP(其实树状数组也行)。

  然后你就可以A掉此题,但代码长度2K以及时间都很不理想。

  然而实际上你A完之后会很震惊--有比你短得多也快得多的O(N)做法。

  首先仍然是两种情况分别处理,假设处理2i-1<2i>2i+1的形式。

  那么你先假设h[1]是要留下的,然后你需要寻找比它大的数。

  如果下一个数刚好比它大,那么就把它作为序列下一个数即可,之后你要寻找比它小的数了(同理进行)。

  否则你就把当前这个数给改掉,改成这个比它小的数,以增加寻找比它大的数的可能性。

  这样贪心去做,复杂度O(N),代码不到线段树的一半。

 

T3:华容道

  这道题拿到题,看到n,m<=30,立即想到BFS。

  由于有用的位置只有两个:目标棋子所在位置,空白格子所在位置,所以状态数最多n^4个,也就是一次BFS的复杂度。

  由于q<=500,然后算了一下复杂度是O(4e8),期望卡卡常数过去,然后T掉了,尝试了好多次无果。

  不得不思考更优的方案了。

  可以发现空格移动次数太多而目标棋子移动的步数并不多,这个冗余可以大量的减掉。

  很快想到,你可以用三维状态i,j,k表示目标棋子在i,j,棋子在其k位置(上下左右)来做(因为不然你目标棋子是动不了的)。

  这样状态数变为n^2*4个,但是问题是你转移一步不是O(1)的了,应该是两次空格位置之间的距离+1(目标棋子与空格交换位置的一步)。

  然后你会考虑去大力地跑bfs来计算空格之间距离(什么floyd,dijkstra,spfa),每个点都去跑一次,O(N^4)预处理出点对两两距离。

  但是你发现这样是有漏洞的,因为你在移动空格的时候,可能一不小心根目标棋子交换了,导致这样的情况出现:空格到了指定位置,目标棋子跑到别的什么地方去了。

  那么你就需要重新规划下预处理。

  由于i到j的距离与j到i的距离其实是一样的,你可以对于每个i,j,k状态都跑一次bfs(注意,中途不能经过i,j点)。

  这样你的预处理仍然是O(N^4)的,但是避免掉了原来的问题。

  然后注意你待会不能再写bfs来转移三维状态i,j,k了,而是要写spfa……

  然后你会写出一个2.5K左右的代码来A掉此题……

posted @ 2017-08-13 15:47  chunlvxiong  阅读(138)  评论(0编辑  收藏  举报