[HAOI2009]逆序对数列(加强)

ZJL 的妹子序列

暴力就是 Θ ( n × m ) \Theta(n\times m) Θ(n×m)
如果 n , m ≤ 1 0 5 n,m \le 10^5 n,m105
考虑问题的转换,设 a i a_i ai 表示 i i i 小的在它后面的数的个数
0 ≤ a i ≤ i − 1 0\le a_i \le i-1 0aii1,显然任何一个满足要求的 a a a 数列都可以从大到小放数字构成一个满足要求的排列
那么就是要求 0 ≤ a i ≤ i − 1 , ∑ i = 1 n a i = m 0\le a_i \le i-1,\sum_{i=1}^{n}a_i=m 0aii1,i=1nai=m 的方案数
考虑生成函数
∏ i = 1 n ∑ j = 0 i − 1 x j \prod_{i=1}^{n}\sum_{j=0}^{i-1}x^j i=1nj=0i1xj
∏ i = 1 n 1 − x i 1 − x \prod_{i=1}^{n}\frac{1-x^i}{1-x} i=1n1x1xi
方法一
L n Ln Ln 后,即
∑ i = 1 n L n ( 1 − x i ) − n L n ( 1 − x ) \sum_{i=1}^{n}Ln(1-x^i)-nLn(1-x) i=1nLn(1xi)nLn(1x)

L n ( 1 − x i ) = − ∑ j = 1 x i j j Ln(1-x^i)=-\sum_{j=1}\frac{x^{ij}}{j} Ln(1xi)=j=1jxij
证明:
L n ( F ( x ) ) = G ( x ) Ln(F(x))=G(x) Ln(F(x))=G(x)
F ′ ( x ) F ( x ) = G ′ ( x ) \frac{F'(x)}{F(x)}=G'(x) F(x)F(x)=G(x)
− i x i − 1 1 − x i = G ′ ( x ) \frac{-ix^{i-1}}{1-x^i}=G'(x) 1xiixi1=G(x)
∑ j = 0 − i x i − 1 x i j = G ′ ( x ) \sum_{j=0}-ix^{i-1}x^{ij}=G'(x) j=0ixi1xij=G(x)
∑ j = 0 − i x i j + i i j + i = G ( x ) \sum_{j=0}\frac{-ix^{ij+i}}{ij+i}=G(x) j=0ij+iixij+i=G(x)
∑ j = 1 − x i j j \sum_{j=1}\frac{-x^{ij}}{j} j=1jxij
证毕
以调和级数的复杂度 Θ ( n l n n ) \Theta(nlnn) Θ(nlnn)求出来后 e x p exp exp 就好了
方法二
∏ i = 1 n 1 − x i 1 − x \prod_{i=1}^{n}\frac{1-x^i}{1-x} i=1n1x1xi
∏ i = 1 n ( 1 − x i ) ( 1 1 − x ) n \prod_{i=1}^{n}(1-x^i)(\frac{1}{1-x})^n i=1n(1xi)(1x1)n
后面的
( 1 1 − x ) n = ( ∑ i = 0 x i ) n (\frac{1}{1-x})^n=(\sum_{i=0}x^i)^n (1x1)n=(i=0xi)n
即就是从 n n n 个不同的集合中间可以重复的取出 i i i 个的方案数的生成函数
那么就是
∑ i = 0 ( n − 1 n + i − 1 ) x i \sum_{i=0}(^{n+i-1}_{n-1})x^i i=0(n1n+i1)xi
考虑前面的
∏ i = 1 n ( 1 − x i ) \prod_{i=1}^{n}(1-x^i) i=1n(1xi)
相当于一个带符号的背包计数问题
而第 i i i 个的体积是 i i i
经典 D P DP DP,就是选出一个上升的序列的方案数
f [ i ] [ j ] f[i][j] f[i][j] 表示选了 i i i 个,和为 j j j 的方案
f [ i ] [ j ] = f [ i ] [ j − i ] − f [ i − 1 ] [ j − i ] f[i][j]=f[i][j-i]-f[i-1][j-i] f[i][j]=f[i][ji]f[i1][ji] (带符号)
考虑到可能有某个的大小超过 n n n
那么 f [ i ] [ j ] + = f [ i − 1 ] [ j − ( n + 1 ) ] f[i][j]+=f[i-1][j-(n+1)] f[i][j]+=f[i1][j(n+1)]
由于每个体积不同,所以最多选出 n \sqrt{n} n
复杂度 Θ ( n n ) \Theta(n\sqrt{n}) Θ(nn )

#include <bits/stdc++.h>
using namespace std;

namespace IO {
    const int maxn((1 << 21) + 1);

    char ibuf[maxn], *iS, *iT, c;
    int f;
    
    char Getc() {
        return (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, maxn, stdin), (iS == iT ? EOF : *iS++)) : *iS++);
    }
    
    template <class Int> void In(Int &x) {
        for (f = 1, c = Getc(); c < '0' || c > '9'; c = Getc()) f = c == '-' ? -1 : 1;
        for (x = 0; c <= '9' && c >= '0'; c = Getc()) x = (x << 3) + (x << 1) + (c ^ 48);
        x *= f;
    }
}

using IO :: In;

const int mod(998244353);
const int maxn(2e5 + 5);

int fac[maxn], ifac[maxn], inv[maxn], n, m, f[500][maxn];

inline void Inc(int &x, int y) {
    x += y;
    if (x >= mod) x -= mod;
}

inline int C(int x, int y) {
    if (y > x) return 0;
    return 1LL * fac[x] * ifac[y] % mod * ifac[x - y] % mod;
}

int main() {
    fac[0] = fac[1] = ifac[0] = ifac[1] = inv[1] = 1;
    for (int i = 2; i <= 200000; ++i) {
        inv[i] = 1LL * (mod - mod / i) * inv[mod % i] % mod;
        fac[i] = 1LL * fac[i - 1] * i % mod;
        ifac[i] = 1LL * ifac[i - 1] * inv[i] % mod;
    }
    In(n), In(m);
    int sz = 500, ans = 0;
    f[0][0] = 1;
    for (int i = 1; i < sz; ++i)
        for (int j = 0; j <= m; ++j) {
            if (j >= i) f[i][j] = (f[i][j - i] - f[i - 1][j - i] + mod) % mod;
            if (j >= n + 1) Inc(f[i][j], f[i - 1][j - n - 1]);
        }
    for (int i = 0; i <= m; ++i) {
        int ret = 0;
        for (int j = 0; j < sz; ++j) Inc(ret, f[j][i]);
        Inc(ans, 1LL * ret * C(n + m - i - 1, n - 1) % mod);
    }
    printf("%d\n", ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值