I. Rooted Tree
整数拆分
五边形数定理
这里的欧拉函数 (phi(q)) 是复变函数
[phi(q) = prod_{k=1}^infty (1-q^k)
]
五边形数定理描述了欧拉函数的展开式特性
[(1-x)(1-x^2)(1-x^3)... = 1 -x-x^2+x^5+x^7-x^{12}-x^{15}+x^{22}+x^{26}+...
]
欧拉函数展开后,有些次方项被消去,只留下次方项为1, 2, 5, 7, 12, ...的项次,留下来的次方恰为广义五边形数。
拆分函数 (p(n))
[sum_{n=0}^{infty}p(n)x^n = prod_{k=1}^{infty}(frac{1}{1-x^k})
]
[1取了多少次->(1+x^1+x^2+x^3+…) \ 2取了多少次->(1+x^2+x^4+x^6+…) \ 3取了多少次->(1+x^3+x^6+x^9+…) \ vdots \ sum_{n=0}^{infty}p(n)x^n = (1+x^1+x^2+x^3+…)(1+x^2+x^4+x^6+…)(1+x^3+x^6+x^9+…) cdots
]
根据欧拉发现的五边形数定理,描述欧拉函(ϕ(x))如下:
[prod_{n=1}^{infty}(1-x^n) = sum_{k=-infty}^{infty} (-1)^kx^{k(3k-1)/2} = sum_{k=0}^{infty} (-1)^kx^{k(3k pm 1)/2} \ (1-x)(1-x^2)(1-x^3) … = 1-x-x^2+x^5+x^7-x^{12}-x^{15}+x^{22}+x^{26}+… \ 这些系数都属于广义五边形数
]
那么我们就很容易发现欧拉函数的导数是分割函数的母函数:
[frac{1}{phi(x)} = sum_{k=0}^{infty} p(k)x^k quad <=> quad 1 = phi(x)sum_{k=0}^{infty} p(k)x^k \ (1-x-x^2+x^5+x^7-x^{12}-x^{15}+x^{22}+x^{26}+…)(1+p(1)x+p(2)x^2+p(3)x^3+…) = 1
]
那么在考虑(x^n)项的系数的时候,在(n>0)的情况下,系数都为0,那么就能得到
[p(n)-p(n-1)-p(n-2)+p(n-5)+p(n-7)+… = 0 \ p(n) = p(n-1)+p(n-2)-p(n-5)-p(n-7)+ …
]
这个的时间复杂度可以在O(nlogn)时间内解决。
暂时不知道怎么 (nlogn) 搞,好像要多项式求逆啥的
待补
但是可以 (O(nsqrt n)) 搞
#include <iostream>
using namespace std;
typedef long long ll;
const ll N = 500005, mod = 998244353;
ll f[N], g[N], dp[N];
int n;
int main() {
scanf("%d", &n);
--n;
for (ll i = 1; i <= n; ++i) f[i] = i * (3*i - 1) / 2;
for (ll i = 1; i <= n; ++i) g[i] = i * (3*i + 1) / 2;
dp[0] = 1;
for (int i = 1; i <= n; ++i) {
for (int j = 1; f[j] <= i; ++j) {
if (j & 1) {
dp[i] += dp[i - f[j]];
if (g[j] <= i) dp[i] += dp[i - g[j]];
} else {
dp[i] -= dp[i - f[j]];
if (g[j] <= i) dp[i] -= dp[i - g[j]];
}
}
dp[i] %= mod;
if (dp[i] < 0) dp[i] += mod;
}
printf("%lld
", dp[n]);
return 0;
}