zoukankan      html  css  js  c++  java
  • [ZJOI2010] 排列计数

    [ZJOI2010] 排列计数 - 组合数学

    Description

    求有多少 (n) 排列满足 (p_i ge p_{[i/2]})

    Solution

    这个性质就是小根堆的性质

    (numleft[i],numright[i]) 表示大小为 (i) 的完全二叉树,其左孩子和右孩子的子树的大小,这个很容易递推出来

    (f[i]) 表示大小为 (i) 的完全二叉树的答案,则 (f[i]=inom{i-1}{numleft[i]} f[numleft[i]]cdot f[numright[i]])

    #include <bits/stdc++.h>
    using namespace std;
    
    #define int long long
    
    int n, m;
    
    int qpow(int p, int q)
    {
        return (q & 1 ? p : 1) * (q ? qpow(p * p % m, q / 2) : 1) % m;
    }
    
    int inv(int p)
    {
        return qpow(p, m - 2);
    }
    
    const int N = 1e6 + 5;
    
    int fac[N], ifac[N], numleft[N], numright[N], f[N];
    
    int ncr(int n, int k)
    {
        return fac[n] * ifac[n - k] % m * ifac[k] % m;
    }
    
    signed main()
    {
        cin >> n >> m;
    
        fac[0] = ifac[0] = 1;
        for (int i = 1; i < min(N, m); i++)
            fac[i] = fac[i - 1] * i % m;
        ifac[min(N, m) - 1] = inv(fac[min(N, m) - 1]);
        for (int i = min(N, m) - 2; i; i--)
            ifac[i] = ifac[i + 1] * (i + 1) % m;
    
    
        for (int i = 2; i <= n; i++)
        {
            int p, q, t = i;
            while (t)
                q = p, p = t & 1, t >>= 1;
            numleft[i] = numleft[i - 1];
            numright[i] = numright[i - 1];
            if (p == q)
                numright[i]++;
            else
                numleft[i]++;
        }
    
        f[0] = 1;
        f[1] = 1;
    
        for (int i = 2; i <= n; i++)
        {
            f[i] = ncr(i - 1, numleft[i]) * f[numleft[i]] % m * f[numright[i]] % m;
        }
        cout << f[n] << endl;
    }
    
  • 相关阅读:
    0316复利计算
    操作系统实验0
    0302-软件工程第一次作业
    1203有穷自动机
    11.11对同学们的作业一些评论
    1029 文法分析
    编译原理第一次上机作业感想
    词法分析编译感想
    0909 初识编译原理
    0909编译原理
  • 原文地址:https://www.cnblogs.com/mollnn/p/14336931.html
Copyright © 2011-2022 走看看