跳到正文
网络寻租
返回

解一道算法题

最近在学算法,看一本算法竞赛书,看到一定阶段来做算法题,随机抽了一道简单的coj 1132来做。

题目是求解一个数的所有除数组合出来的数之和(不包括自己),比如:20 = 2 * 2 * 5,结果a(20) = 1 + 2 + 4 + 5 + 10 = 22。

首先我采用硬解的方法,求出所有的除数,然后排列组合一下。发现超时了。 回去看了一下题目,发现:测试用例数量equal to about 2*10^5,硬算的复杂度大概是n^3*log(n),难怪算不出来,只能去优化算法了。

排列组合题目一般来说会有重合子问题,可以用动态规划来优化。先列出状态转移方程看看:

假设要求解a(n),n可以拆分成除数d1, d2, … dk (dk > dk-1),每个除数的数量是m1, m2, …, mk,那么a(n)结果和a(p)相关,其中p = d1^m1 * d2^m2 ... * dk-1^mk-1,拆分一下a(n):

a(n) = sum( d1^s1 * d2^s2 * ... * dk-1^sk-1 * dk^sk ) (所有可能的 sk <= mk)
     = d1^m1 * ... * dk-1^mk-1 + sum( d1^s1 * ... * dk-1^sk-1 ) * dk^sk
     = p + a(p) * (1 + dk + dk ^ 2 + ... + dk ^ mk)
     = p + a(p) * (1 - dk^(mk+1)) / (1 - dk)
     

题目中进行了大量运算(n < 5*10^5 ,其中2/5的值都需要求解),n利用到旧的p的概率很大, 又能够减少一个级别的复杂度,缓存a(p)的值到数组就可以了。

写程序的方法:每次计算a(n)都会先拆分除数列表,保存到一个vector数组里面。 然后调用a(p),算出来的结果缓存到一个结果数组中。

之后进行优化:

代码在这里。 我的答案时间消耗比最快的算法多将近一倍,不知道大家有什么更好的算法没有?

结论:

解算法题比CRUD有意思多了。


分享这篇文章:

上一篇
programming chaos
下一篇
factorio介绍

评论

评论通过 GitHub 账号发布,需要先使用 GitHub 登录。