zoukankan      html  css  js  c++  java
  • [HAOI2009]逆序对数列(加强)

    ZJL 的妹子序列

    暴力就是 (Theta(n imes m))
    如果 (n,m le 10^5)
    考虑问题的转换,设 (a_i) 表示 (i) 小的在它后面的数的个数
    (0le a_i le i-1),显然任何一个满足要求的 (a) 数列都可以从大到小放数字构成一个满足要求的排列
    那么就是要求 (0le a_i le i-1,sum_{i=1}^{n}a_i=m) 的方案数
    考虑生成函数

    [prod_{i=1}^{n}sum_{j=0}^{i-1}x^j ]

    [prod_{i=1}^{n}frac{1-x^i}{1-x} ]

    方法一
    (Ln) 后,即

    [sum_{i=1}^{n}Ln(1-x^i)-nLn(1-x) ]

    [Ln(1-x^i)=-sum_{j=1}frac{x^{ij}}{j} ]

    证明:

    [Ln(F(x))=G(x) ]

    [frac{F'(x)}{F(x)}=G'(x) ]

    [frac{-ix^{i-1}}{1-x^i}=G'(x) ]

    [sum_{j=0}-ix^{i-1}x^{ij}=G'(x) ]

    [sum_{j=0}frac{-ix^{ij+i}}{ij+i}=G(x) ]

    [sum_{j=1}frac{-x^{ij}}{j} ]

    证毕
    以调和级数的复杂度 (Theta(nlnn))求出来后 (exp) 就好了
    方法二

    [prod_{i=1}^{n}frac{1-x^i}{1-x} ]

    [prod_{i=1}^{n}(1-x^i)(frac{1}{1-x})^n ]

    后面的

    [(frac{1}{1-x})^n=(sum_{i=0}x^i)^n ]

    即就是从 (n) 个不同的集合中间可以重复的取出 (i) 个的方案数的生成函数
    那么就是

    [sum_{i=0}(^{n+i-1}_{n-1})x^i ]

    考虑前面的

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

    相当于一个带符号的背包计数问题
    而第 (i) 个的体积是 (i)
    经典 (DP),就是选出一个上升的序列的方案数
    (f[i][j]) 表示选了 (i) 个,和为 (j) 的方案
    (f[i][j]=f[i][j-i]-f[i-1][j-i]) (带符号)
    考虑到可能有某个的大小超过 (n)
    那么 (f[i][j]+=f[i-1][j-(n+1)])
    由于每个体积不同,所以最多选出 (sqrt{n})
    复杂度 (Theta(nsqrt{n}))

    #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
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    hdu 1856 More is better(并查集)
    hdu 1787 GCD Again
    hdu 1203 I NEED A OFFER!(dp||背包)
    hdu 1208 Pascal's Travels(dp)
    hdu 1142 A Walk Through the Forest(dijkstra)
    hdu 1087 Super Jumping! Jumping! Jumping!(dp)
    Jquery插件
    在ashx文件中使用Session
    页面注册js的方法比较
    Linq体验(一)
  • 原文地址:https://www.cnblogs.com/cjoieryl/p/9896102.html
Copyright © 2011-2022 走看看