【动态规划 | 数学】整数划分

把正整数n分成若干个正整数之和的方法数。

http://www.51nod.com/Challenge/Problem.html#problemId=1259

动态规划

答案是g[n]

const int MAXF = 1e3 + 10;
const int MAXG = 2e5 + 10;

int n;
ll f[MAXF], g[MAXG];

void calc() {
    f[1] = 1, f[2] = 2, f[3] = 5, f[4] = 7;
    for(int i = 5; i < MAXF; ++i)
        f[i] = ((3 + 2 * f[i - 2] - f[i - 4]) % MOD + MOD) % MOD;
    g[0] = 1;
    for(int i = 1; i <= MAXG; ++i) {
        for(int j = 1; f[j] <= i; ++j) {
            if((j + 1) >> 1 & 1)
                g[i] = (g[i] + g[i - f[j]]) % MOD;
            else
                g[i] = (g[i] - g[i - f[j]] + MOD) % MOD;
        }
    }
}

\(O(n\sqrt{n})\)

生成函数

\(O(n\log n)\)

易知整数划分的生成函数为

\(F(x)=\prod\limits_{i=1}^{n}\frac{1}{1-x^i}\)

但是这个很难算,看到右边是乘积的形式,考虑两边取对数

\(\ln (F(x))=\ln (\prod\limits_{i=1}^{n}\frac{1}{1-x^i})\)
\(=\sum\limits_{i=1}^{n} \ln\frac{1}{1-x^i}\)
\(=-\sum\limits_{i=1}^{n} \ln(1-x^i)\)

考虑模 \(x^n\) 下的麦克劳林展开

\[\ln(1+x)=\sum\limits_{i=0}^{n}(-1)^{i+1}\frac{x^{n}}{n} \]

代入 \(x:=-x^k\)
\(\ln (F(x))=-\sum\limits_{k=1}^{n} \ln(1-x^k)\)
\(=-\sum\limits_{k=1}^{n} \sum\limits_{i=1}^{n}(-1)^{i-1}\frac{(-x^k)^{i}}{i}\)
\(=\sum\limits_{k=1}^{n} \sum\limits_{i=1}^{n}\frac{x^{ki}}{i}\)
\(=\sum\limits_{T=1}^{n} x^T \sum\limits_{k=1}^{n} \sum\limits_{i=1}^{n}\frac{1}{i}[T=ki]\)
\(=\sum\limits_{T=1}^{n} x^T \sum\limits_{k|T} \frac{1}{k}\)

然后再取指数函数即可。

int n;
int A[MAXN], B[MAXN];

int calc(int n) {
    fill(B, B + n + 1, 0);
    for(int i = 1; i <= n; ++i) {
        int invi = qpow(i, MOD - 2);
        for(int j = i; j <= n; j += i)
            B[j] = qadd(B[j], invi);
    }
    polyexp(B, n + 1, A);
    return A[n];
}

可惜因为对多项式的操作,对模数有一定要求。正常版本是使用FNTT的,不能应对不存在原根的模数(如1e9+7)。

若干个不同正整数之和
http://www.51nod.com/Challenge/Problem.html#problemId=1201

上一篇:linux ln -s


下一篇:[整理][持续更新]多项式知识点大全(超简洁!)