【NOI2019模拟2019.6.27】B (生成函数+整数划分dp|多项式exp)

Description:


\(1<=n,k<=1e5,mod~1e9+7\)

题解:


考虑最经典的排列dp,每次插入第\(i\)大的数,那么可以增加的逆序对个数是\(0-i-1\)

不难得到生成函数:

\(Ans=\prod_{i=0}^{n-1}(\sum_{j=0}^ix^j)[x^k]\)

\(=\prod_{i=1}^{n}{1-x^i\over 1-x}[x^k]\)

分母是一个经典的生成函数:

\({1\over 1-x}^n=(\sum_{i>=0}x^i)^n=\sum_{i>=0}C_{i+n-1}^{n-1}\)

那么问题就变为了求:

\(\prod_{i=1}^{n}{1-x^i}\)的前k项。

考虑利用整数划分dp,相当于把k划分成若干不同且<=n的数和,系数是\((-1)^{数的个数}\)

不难得出dp:

\(f[i][j]\)表示已经划分了i个数,和为j的所有方案系数和。

转移\(f[i][j]=f[i][j-i]-f[i-1][j-i]+f[i-1][j-(n+1)]\)

由于\(i<=\sqrt {2k}\),所以复杂度是\(O(k\sqrt k)\)

另一种多项式exp的做法:

不妨对这个式子进行ln最后再exp回去。

我们知道有:

\(ln(1+x)\)

$=\int ~ln(1+x)' $

\(=\int~{1\over 1+x}\)

\(=\int ~ \sum_{i>=0}(-1)^ix^i\)

\(=\sum_{i>=1}{(-1)^{i-1}x^i\over i}\)

\(Ans=exp(\sum_{i=1}^n(ln(1-x^i)-ln(1-x)))[x^k]\)

\(ln(1-x^i)=\sum_{j>=1}{(-1)^{(j-1)i}x^{ij} \over j}\)

所以暴力展开只有调和级数个有用项。

\(ln(1-x)\)同理暴力展开后乘上n即可。

复杂度\(O(n~log~n)\),但是要写MTT,所以跑得巨慢,又难写。

Code:

#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i <  B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;

const int mo = 1e9 + 7;

ll ksm(ll x, ll y) {
    ll s = 1;
    for(; y; y /= 2, x = x * x % mo)
        if(y & 1) s = s * x % mo;
    return s;
}

const int N = 1e5 + 5;

int n, k, m;
ll fac[N * 2], nf[N * 2];
ll f[450][N];
ll g[N];
void calc(int n) {
    fac[0] = 1; fo(i, 1, n) fac[i] = fac[i - 1] * i % mo;
    nf[n] = ksm(fac[n], mo - 2); fd(i, n, 1) nf[i - 1] = nf[i] * i % mo;
}
ll C(int n, int m) {
    return fac[n] * nf[n - m] % mo * nf[m] % mo;
}

int main() {
    freopen("b.in", "r", stdin);
    freopen("b.out", "w", stdout);
    calc(200000);
    scanf("%d %d", &n, &k);
    m = sqrt(2 * k);
    f[0][0] = 1;
    fo(i, 1, m) {
        fo(j, i, k) {
            f[i][j] = f[i][j - i] - f[i - 1][j - i];
            if(j >= n + 1) f[i][j] += f[i - 1][j - (n + 1)];
            f[i][j] %= mo;
        }
    }
    ll ans = 0;
    fo(i, 0, k) {
        fo(j, 0, m) g[i] += f[j][i];
        g[i] %= mo;
        ans += g[i] * fac[n - 1 + (k - i)] % mo * nf[k - i] % mo;
    }
    ans = (ans % mo * nf[n - 1] % mo + mo) % mo;
    pp("%lld\n", ans);
}

猜你喜欢

转载自www.cnblogs.com/coldchair/p/11122836.html