Sum - ACM PKU 1844 解题报告

来源:互联网 发布:sql explain 怎么看 编辑:程序博客网 时间:2024/05/18 04:46

问题描述:Consider the natural numbers from 1 to N. By associating to each numbera sign (+ or -) and calculating the value of this expression we obtaina sum S (0< S <= 100000). The problem is to determine for a given sum S the minimumnumber N for which we can obtain S by associating signs for all numbersbetween 1 to N.For a given S, find out the minimum value N in order to obtain S according to the conditions of the problem.

这个问题初一看,似乎是一道动态规划题:对某一个 n,如果为 n 加上负号,则问题变成在 1 ~ n-1 中加上正负号使得其和为 S+n;如果为 n 加上正号,则子问题为 1 ~ n-1 中加上正负号使其和为 S-n。因此,可以记状态 f(n,s) 表示能否用 1 到 n 这些数通过加上正负号得到和 s,则

      f(n,s) = f(n-1,s+n) and f(n-1,s-n);

      f(n,s) = false  if  n*(n+1)/2 < |s|

为了求解N,我们只需要从 1 开始枚举,直到第一个 N 使得 f(N,S)=true。时间复杂度是 O(N*S + N3)。 N3 这个项是因为,状态中 f(n,s) 的 s 最多只有 s + n*(n+1)/2 那么大(这是悲观估计了,但复杂度的话应该是一样的)

分析到这里,似乎问题解决了,但其实不然:复杂度中的 N 是事先不知道的!更糟的是,状态空间看起来未必是有限的!我们从 1 开始枚举 f(i,S),但我们会在哪里结束呢?会不会对某个 S,不存在这样的 N?即使对每个 S 都有解存在,那么会不会 N 随 S 的增长速度是指数级的,甚至更快?如果是这样的话,对于较大的 S,这个方法就不现实了。

事实上,结果总算不是太坏:N =  O(S) !因此上述动态规划算法的时间复杂度是 O(S3)。为什么 N=O(S)?对于给定的 S,考虑 1~ 2S,给奇数加上负号,给偶数加上正号,其和正好是 S。因此, N <= 2S。对于这样复杂度的算法,想 AC POJ1844 估计还是有困难的(本人还没试过,有空去试试~)

除了动态规划,还可以考虑搜索,但剪枝效果值得怀疑。本人不才,暂时没想出很有效的剪枝,也懒得想了,有谁知道的请不吝留言相告。

事实上,我刚看到这道题目时,第一个想到的不是动态规划,也不是搜索,而是数学上的解析解。这题带有太明显的数论痕迹,不让人想到数论都难啊。一开始想的是素因子:无论是正是负,本质上就是加上或减去某个素因子的倍数。然而,此路似乎走不通。于是转而考虑奇偶性。事实证明,这是一条捷径啊!

首先,N*(N+1)/2 >= S。这是显然的。前 N 个数的和最大也就 N*(N+1)/2。如果 N*(N+1) < S,则 N 显然不可能是解。如果等号成立,则 N 是解。现在假定 n 为使得 max = n*(n+1)/2 >= S 成立的最小整数。记 Q 为 1~n 对某些数添加负号后所得的和。

当 max 严格大于 S 时,直觉上,可以通过对其中的某些元素添加负号,即减去某些数,让 Q 变小直到等于 S。考虑对 1~n 中某个数 x 添加负号,则 Q = max - 2*x。一个非常重要的观察就是 Q 的奇偶性和 max 是一样的!简单的归纳法表明 Q 和 max 的奇偶性始终保持一致。如果 max 和 S 的奇偶性不同,则 Q 不可能等于S,因而 n 显然不会是解。

现在先假定 max 和 S 的奇偶性一样。考虑 d = max - S。则 d 为偶数,于是  d/2 正好为整数。由于  n 是使得 n*(n+1)/2 >= S 的最小整数,则 d < n,于是 d/2 < n。因此,只需要把 d/2 这个数变成负的就可以使得 Q=S。同时,由于 n 的最小性,n 为解 N。

最后考虑 max 和 S 的奇偶不一样。于是 n 不是解。考虑 n+1。如果 n+1 是奇数,则 max 的奇偶性发生变化,并且和 S 一样,于是根据上述论述,N=n+1;如果  n+1 是偶数,则 max 的奇偶性不变,n+1 也不可能是解,但 n+2 是奇数,于是,N=n+2。

时间和空间复杂度呢?都为 O(1) !至此,问题得到近乎完美的解答。根据这个方法也出的代码,也是相当的短小。由于代码很短,我就用代码代替伪代码了

后记:数学真强大啊!用常数时间解决了一个看似复杂度很高的问题!后来在该题目的讨论区也看到了几乎相同思路的短代码。那个代码非常短,但牺牲了速度:从 1 开始累加,直到遇到第一个 n,使得 d=max-S 大于 0 且其为偶数。其时间复杂为 O(N),或者说 O( S1/2)。个人还是比较喜欢复杂度低的代码,虽然优雅程度不足,但却是最优的。

原创粉丝点击