多集的数量,这样从1到


11

我的问题。给定,我想计算有效多集S的数量。多重集S在以下情况下有效nSS

  • 的元素之和为n,并且Sn
  • n的每个数字都可以唯一地表示为S的某些元素的总和。1nS

例。 例如,如果然后{ 1 1 1 1 1 } { 1 2 2 } { 1 1 3 }是有效的。n=5{1,1,1,1,1},{1,2,2},{1,1,3}

然而,是无效的,因为2可以通过形成两个{ 1 1 }{ 2 }(即,2可以被表示为两个2 = 1 + 12 = 2) ,因此第二个条件不成立。类似地3能够通过形成{ 2 1 }{ 1 1 1 }S={1,1,1,2}{1,1}{2}2=1+12=2{2,1}{1,1,1}

}也无效,因为从所有数字 1 5都可以被唯一制成,但的元素之和小号不是 5S={1,2,415S5


我试图为这个问题找到一个好的算法已经有一段时间了,但是无法解决。它来自codechef。我已经看到了一些提交的解决方案,但是仍然无法获得解决问题的逻辑。注意:问题的时限为10秒,n<109

对于多集,我将使用符号a i < a j如果i < j,这意味着a i在多集S中出现c i次。S={(a1,c1),(a2,c2)...} ai<aji<jaici

到目前为止,我已经得出了一些结论

  • 所需的已排序多重集的第一个元素应为1
  • 是一组以下两个属性然后ř < ķ 一个[R + 1 = 一个ř  或  Σ [R = 0+ 1S={1,a2ak}|a1a2akr<k  ar+1=ar or (i=0rai)+1
  • ,其中一个正在发生Ç 倍,如下所要求的特性然后从上面的结论我们可以说,一个| n + 1S={(1,c1),(a2,c2)(ak,ck)}|a1a2akaicii ai|n+1如果 Ĵ > 。 证明:一个+ 1 = 一个ç + 一个 - 1 + 1 一个| 一个+ 1ai|ajj>i
    ai+1=(aici+ai1)+1ai|ai+1
  • 现在考虑即,所有1之后的后续数字将是d的倍数。所以让f n S={1,11d1,d,dd,dm1,dm1dm1,dm2,dm2dm2,}df(n)是可能的此类多重集的计数,则其中,我求和的所有可能数量1'小号=d-1)。换句话说,fn1=gn=d| ndngdf(n)=d|n+1,d1f(n(d1)d)1s=d1f(n1)=g(n)=d|n,dng(d)

最终,我的问题归结为这一点-有效地找到,使其不超过时间限制。g(n)


2
您是否检查了要求其他人公开发布练习问题的解决方案和算法是否合适?Codechef FAQ 似乎期望解决方案不会公开发布(除了一些非常基本的问题之外)。在这里发布解决方案是否会“浪费”他人的实践问题,还是可以吗?我对Codechef社区的规范和礼节不熟悉。
DW

我没有发现与不在常见问题上在公共领域发布问题相关的任何信息,并且此限制是针对正在进行的竞赛问题,而不是针对练习问题。
正义联盟

1
@DW我不认为他们会介意我们讨论不是来自正在进行的比赛的问题。
拉维·乌帕德海伊

1
您正在寻找输入数字的分区数。我建议您使用此流行语进行一些研究。
拉斐尔

2
@Raphael,我同意,发布者应该阅读这些技术。问题不完全相同-张贴者的第一个条件要求这是一个分区,但是第二个条件施加了额外的限制(用于唯一的更改)-但可能可以使用与计数次数相同的技术分区,并进行了一些修改以应对其他要求。
DW

Answers:


2

这是最快的解决方案正在做的事情。它确实在计算您的函数 鉴于 Ñ,我们因子(见下文),然后计算所有因素(见下文) ˚F 1... ˚F 以某种顺序,使得 ˚F | ˚F Ĵ意味着Ĵ(属性P)。现在,我们通过按给定顺序遍历因子,根据公式计算 g。属性P确保当我们计算 g d )时,我们已经为所有非平凡因子 e计算了 g e

g(n)=dnd<ng(d),g(1)=1.
nf1,,fmfi|fjijgg(d)g(e)e。还有一个优化(见下文)。d

更详细地讲,我们按顺序遍历这些因子,对于每个因子,我们通过检查f 1... f i 1中的哪一部分除以f i来找到其所有非平凡因子。fif1,,fi1fi

分解:预处理:我们使用Eratosthenes筛子列出以下的所有素数。给定n,我们仅使用试验除法。109n

生成所有因素:这是递归完成的。假设。我们运行嵌套循环1{ 0 ... ķ 1 } ... { 0 ... ķ },并输出p 1 1p 。您可以通过归纳证明性质P。n=p1k1ptkttl1{0,,k1},,lt{0,,kt}p1l1ptlt

优化:由于该程序在多个输入上运行,因此我们可以使用备忘录来节省不同输入之间的时间。我们仅存储较小的值(最多),这使我们可以将所有存储的值存储在数组中。该数组用零初始化,因此我们可以知道哪些值是已知的(因为所有计算值均为正值)。105


如果的因式分解p ķ 1 1... p ķ ,然后˚F Ñ 仅取决于ķ 1... ķ ,并且实际上只在该载体中的排序的版本。每个低于10 9的数字最多具有29个素数(重复),并且由于p 29 = 4565,计算f似乎是可行的n+1p1k1,,ptktf(n)(k1,,kt)10929p(29)=4565f(或更确切地说)递归地。如果有许多不同的输入,则此解决方案可能会更快。实际上,最多为10个g10

将分区映射到相应此函数也可能具有明确的分析形式。例如,g p k= 2 k - 1g p 1p tA000670给出,g p 2 1 p 2p tA005649A172109给出gg(pk)=2k1g(p1pt)g(p12p2pt)


1

好的,所以您有一个的递归关系(请参阅问题的结尾)。g()

在这一点上,似乎一种自然的方法是记下递归算法以计算并应用记忆,这样您就不会重复计算g i 。换句话说,当你计算,则其存储在映射哈希表 ; 如果以后需要再次知道g i ,可以在哈希表中查找它。g(n)g(i)g(i)ig(i)g(i)

这确实需要保,但也有保高效的算法ňñ 10 9nnn109

你也可以查找序列整数序列的在线百科全书。如果您在其百科全书中找到了序列,有时他们会提供其他有用的信息(例如,用于计算序列的有效算法)。诚然,这可能会使事情变得无趣。g(1),g(2),g(3),g(4),g(5),


0

这是一个入门的提示。应用标准的动态编程算法来枚举整数分区,并添加一些逻辑以通过迭代检查所有和,进行更改并验证唯一性来检查哪些允许唯一更改。

在一些详细信息:假设你有一个多集。鉴于一些1 ñ,你怎么能确定的SUBMULTISET 小号,总结到?您如何检查该子多重集是否唯一?尝试采用标准的动态编程技术进行更改。(另请参阅此问题。)Si1inSi

SnS

P(n)P(1),P(2),,P(n)P(n+1)


这是一种可能会更好的方法。

SnTSTn

xSSTxSSTn

SA[1|S|,1n]A[i,j]jiSiSSS={s1,s2,,sk}s1s2skA[i,j]A[1i1,1j1]A[i,j]=A[i1,j]A[i1,jsi]j>siA[i,j]=A[i1,j]S

TSSTnSnTn+1,n+2,,nTAA[1|T|,1n]A[|T|,n+1],A[|T|,n+2],,A[|T|,n]TS

Snn20P[120]P[5]SP[n]Sn

P[n]P[1]{1}nSP[n]TSnTTP[n]n20

这应该是可行的。祝好运!玩得开心!仔细研究细节将是动态编程中的良好学习练习。


n
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.