#include <iostream>
#include <vector>
using namespace std;
void genPart(size_t N) {
vector<size_t> Penta;
Penta.emplace_back(1);
vector<size_t> Part;
Part.assign(N + 1, 0);
Part[0] = 1;
for (size_t i = 1, j = 1; i <= N; i++) {
size_t nextPenta = Penta[j - 1] + ((j + 1) >> (j & 1));
if (nextPenta == i) {
Penta.emplace_back(nextPenta);
j++;
}
for (size_t k = 0; k < Penta.size(); k++) {
if (k & 2) {
Part[i] -= Part[i - Penta[k]];
}
else {
Part[i] += Part[i - Penta[k]];
}
}
cout << "Part " << i << " is: " << Part[i] << '\n';
}
}
int main() {
size_t n;//n <= 416
cout << "Enter the number: ";
cin >> n;
genPart(n);
return 0;
}
这个代码利用了五边形数的规律,即数列1,2,5,7,12,15,22,26……
我们可以推导出这个数列的递推公式:A[1]=1,A[2n]=A[2n-1]+n,A[2n+1]=A[2n-1]+2n+1。
从而根据下角标奇偶性的不同,我们可以得出A[n]=A[n-1]+(n >> ((n - 1) & 1))
即当n为偶数时,A[n]等于前一个数加上n/2,当n为奇数时,A[n]等于前一个数加上n
但是为了让代码看起来更统一,我们将下角标往前移一个,令Part[0]=1,便有了
nextPenta = Penta[j - 1] + ((j + 1) >> (j & 1))
在计算整数分割数的部分,我们利用了五边形数与整数分拆数的递推关系
p(k)=p(k−1)+p(k−2)-p(k−5)-p(k−7)+...
至于这个关系的证明过程,可以网上搜索,这里就不过多赘述。
符号的变换关系是++--,正好可以和利用k&2来判断
整体的时间复杂度是O(n^(3/2)),空间复杂度是O(n)
如果你们有更好的算法,还请多多指教,也许算单个整数分拆数的还有更好的算法,但是打表的写法我目前为止,也就只能写到这了。