埃及分数
迭代加深搜索
题意:将一个分数拆分成几个分子为 1 的分数的和。要求拆分出的个数最少。
正解:据说是黑书上的题目。思路很明确,用 ID-DFS 每次限定深度进行搜索即可。
为了使序列不重复,每次找到的分数都要比前一个分数小,即分母比前一个分数的分母大。同时要保证当前的分数加上之前的分数之和不大于题目给出的分数。这样我们就确定了每层搜索枚举的上下界。最终判断枚举出的分数序列是否满足要求时只要进行通分相加即可。
选举组长
哈希表或部分排序
题意:有 N 个候选人,有 M 个人参加选举,规定得票超过半数的人当选组长。N<=2^31,M<=10^6。
正解:
法一:我们注意到 N 虽然很大但是 M 相比之下显得很小。所以我们可以用一个哈希表(模 10000007)保存每个人的得票,用开链法解决冲突,可以实时判断是否已经产生了组长。
法二:如果有人的得票超过半数,那么将选票排序后,此人的编号一定占据了一个大于 M/2 的区间。那么,无论这个区间分布在哪里,M/2 这个点必然会被这个区间覆盖。所以,问题就转化成了求序列中第 M/2 个大的数,并统计其在整个序列中出现了多少次。用不完全的快排就可以完成(详见 http://www.cnblogs.com/lsdsjy/p/3549377.html)。
环形最大子串和
贪心
题意:给出一个环形整数串,求最大连续和。
初步解法:把整个串复制一遍,然后套用求最大连续和的贪心方法。只是如果当前累加的元素个数已经超过了 n 就停止累加。其实很明显是错的。
正解:这个问题与最大连续和的最大区别在于环。也就是说最大连续和可能是由整个序列的最后一部分与最前一部分组成的。那么我们只要单独考虑这种由两部分组成最大连续和的情况即可。可以用动规求出从第一个位置开始的最大连续前缀和与以最后一位结束的最大连续后缀和,枚举断开点,将其相加,与贪心法得到的答案进行比较即可。
还有更巧妙的解法是,用贪心法统计出序列的最大与最小连续和,记为 smax 和 smin。所有元素的和为 sum,那么最后结果就是 max(smax, sum-smin)。在有负数的情况下,smin 是所有区间中和小于 0 且最小的区间和,那么将其「取反」就能得到一个「极大区间和」。
好斗的奶牛
二分枚举+贪心
题意:给出一条直线上的一些点,选取其中的一部分使得最近的两个点距离最远。
正解:这种问题很明显是用二分枚举答案去做。但是如何判断一个方案是否可行呢?我最开始的想法是将直线上的每个点变成无向图中的顶点,计算出两两之间的距离作为边权,枚举出一个值后删去图中大于它的边,判断图中最大的连通分量的顶点个数是否足够。但是题目的数据规模不允许这样做。
然后经 LZW 大神指点明白了如何判断方案的可行性:对于一条直线上前后两个不同的点,假如它们都可以选取,那么显然选取前面的点会使得解更优。所以只要顺序枚举直线上的点,能取就取,如果能取够,说明方案可行。
三值排序
贪心
题意:给定一个只有 1、2、3 的数字序列,要求用最少的交换次数使其有序。
初步解法:首先,如果有 (1, 2) 或 (2, 3) 或 (1, 3) 这样的二元组错位,只需要 1 次交换就能纠正两个元素的位置,是最优的决策。那么我们顺序扫描序列,对于一个元素 ai,如果它已经在它应该在的位置(通过对原序列排序可以判断)显然不用进行操作;否则,扫描整个序列,尝试找到另外一个元素,刚好与 ai 构成一个错位的二元组,进行交换;如果无法找到,就将它交换到任意一个正确的位置,不管该位置上的数字是什么。这样的做法可以 AC,但无法证明后面这个决策的正确性。
正解:首先,肯定要先找到所有的错位的二元组,因为只需 1 次交换让两个元素归位,「最合算」。在找完所有的二元组后,剩下的数必然可以用某种方案划分成许多 (1, 2, 3) 整个错位的三元组(如果无法划分,那么必然还能找到错位的二元组)。那么最优的方案就是分别用 2 次交换纠正这些三元组。即剩余的元素数/3*2. 再加上二元组的个数就是最后的答案。
二进制除法
数论
题意:求一个超大二进制数(长度<=200000)对一个较小的二进制数(位数<=20)取模的结果。
初步解法:没什么思路,直接高精度搞,写了很久。最后被一些数据坑了(有前导0)。
正解:看了标程之后感觉自己同余定理白学了。
因为后面这个数比较小其实可以想到用同余定理,将前面这个超大的数进行拆分,拆分为一些数字的乘法和加法操作,在乘法和加法的同时进行取模。
以 101001 mod 10 为例。(10)2 = (2)10,(101001)2 mod (10)2 = ((((1 mod 2)*2 mod 2 + 0 mod 2) + 1 mod 2) mod 2 + 0 mod 2) mod 2 + ...
这样中间结果就始终不会超过 int 的范围。
乘积最小路径
最短路
题意:求无向图中边权乘积最大的路径。点权<=maxlongint。
分析:经 zbt 大神指点明白,可以对所有的边权进行取对数操作。然后就是裸的最短路了。
据说还有一种更逆天的做法是用 Pascal 的 extended 类型直接算乘积。据 zbt 大神说可以算到 10 的上千次。因为这道题对精度的要求不会太高,也算是一种投机取巧的做法。