05年的题目绝对是自2000年以来难度最大的。后三题的难度系数分别为0.2、0.2、0.3,而前面几年的题目中每年最多只出现一道难度系数为0.2的题目,其难度可见一斑。
强烈推荐这个 PPT,每道题都讲得很清楚:http://wenku.baidu.com/view/878beb64783e0912a2162aa7.html
第一题:谁拿了最多奖学金
模拟
第二题:过河
动态规划+优化
首先看到题目的数据范围就已经让人心生畏惧了。1e9这么大的数字,无论从空间还是时间都无法承受。
动态规划是很容易就能想到的。
用 f(i) 表示跳到i点时最少踩到的石子数,则
f(i) = min(f(i-s), f(i-s+1), … , f(i-t)) + stone(i)
(stone(i) 用于表示i点处是否有石子,若有则为1,否则为0)
虽然题目给出的数据范围表示30% 的数据在1e5以内,但是用这种方法只能得到10分。(也许是因为我在一些细节的地方写错了)
然后如何进行优化?
我们注意到L可能达到1e9,而石子数最多不超过10,所以可以肯定,(算上起点和终点)至少有两个点之间的距离比较大,而S和T比较小,则对于较大的一段距离而言,无论怎样都能跳过中间部分而不踩到石子,也就是说这一段距离内的大部分点即使不进行计算也不会对最终结果产生影响,而能对结果产生影响的区间分布在石子附近。所以我们可以把两个石子之间的距离缩短,去除中间那些无关紧要的部分。
关于如何缩短距离有很多方法,比如当两点距离大于100时将它缩短等等。但是缩短到多少呢?
事实上对于每个石头所在的点i,会影响其结果的点是:i-T, i-T+1, ..., i-S-1, i-S. 所以至少要给它留出T的空段,当然最好是前后各有T,所以可缩短到2T或以上。
第三题:篝火晚会
找规律
首先,判断是否有解是比较容易的:如果有一个人 A 想和 B 相邻,但 B 不想和 A 相邻,那么必然无解。
由于没有思路,我判断了无解之后就直接交了,10 分。
为了方便处理,要把一个长度为 n 的环拆成 2n 条链。因为从每个点出发都可以由两个方向得到两条链。
然后,在有解的情况下,我们可以构造出最终状态。我们要做的就是从初始状态变换到最终状态。初始状态和最终状态各有 2n 种,我们要求出从一种初始状态到一种最终状态最少的变换步数。两个状态之间的变换步数很明显等于错位的元素个数。如果直接枚举计算,复杂度是 O(2n*2n*n)。可以拿 30 分。
我们可以换一种思考方式,把「找最少的错位元素个数」变为「找最多的不动元素个数」。也就是说从一个状态到另一个状态,变换步数=总元素个数-位置正确的元素个数。同时我们注意到,初始和最终状态的各种形式中,元素的相对位置是不会改变的。那么我们对于每个元素,对其现在位置与应该在的位置作差(如果是负数就加上 n),记为 v[i]。那么对于 v 值相同的元素,我们总能找到另一种状态,它们的 v 值都为 0。 那么我们只要在任意一种状态里找 v 值相同的元素即可。我们找到最多有多少元素的 v 值相等,记这个最多的个数为 max,那么这些数在某个状态下肯定是不用移动的,所以变换步数就为 n – max。注意要同时考虑逆序的情况,也就是说在初始状态中取一种,在最终状态中取一种以及其倒序,对这两种统计 v 值。
第四题:等价表达式
表达式求值
关于基本的中缀表达式求值问题详见此文: http://www.cnblogs.com/dolphin0520/p/3708602.html 。这篇文章说得很好。总结起来如下:
建立两个栈:操作数栈和运算符栈。每次遇到数字就入栈,遇到操作符的情况下,如果该操作符的优先级高于栈顶操作符的优先级就入栈,否则就不断将操作数和栈顶操作符出栈计算值然后将值入栈,直到栈顶操作符的优先级低于当前操作符。注意对括号的特殊处理。我的处理方式是对于左括号让其入栈,如果遇到右括号就不断弹栈计算,直到遇到左括号,然后将左括号出栈,右括号也就不用入栈了。
然后,判断两个表达式是否等价有两种方法:
- 代入具体的值并计算,重复几次,如果相等就基本可以判断是等价的表达式;
- 将表达式展开,判断各项是否相等。
第一种方法实现起来不难,查找 a 并替换成数字即可。
对于第二种方法,我们可以用一个数组 co 来表示一个多项式。co[i] 表示 ai 的系数。所以 co[0] 表示的就是常数项,co[1] 表示一次项的系数,以此类推。这样一来四则运算不成问题。问题的纠结之处在于 co 数组开多大合适。我是看了数据之后才发现居然有 ^5^10 这样逆天的运算。所以把 co 数组大小开到了 200 就 AC 了。
注意两种方法得到的中间结果都有可能爆 long long,所以最好要 mod 一个比较大的数。