zoukankan      html  css  js  c++  java
  • [BZOJ 2111][ZJOI2010]Perm 排列计数(Lucas定理)

    Description

    称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很大,只能输出模P以后的值

    Solution

    可以先发现这个排列其实是一个小根堆

    F[i]=C(siz[i]-1,siz[i<<1])*F[i<<1]*F[i<<1|1]

    组合数的部分可以用Lucas解决

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #define MAXN 1000005
    using namespace std;
    typedef long long LL;
    int n,P,siz[MAXN],f[MAXN];
    LL inv[MAXN],fac[MAXN];
    void init()
    {
        fac[0]=1,inv[1]=1;
        for(int i=1;i<=n;i++)
        fac[i]=fac[i-1]*i%P;
        for(int i=2;i<=n;i++)
        inv[i]=inv[P%i]*(P-P/i)%P;
        inv[0]=1;
        for(int i=1;i<=n;i++)
        inv[i]=inv[i-1]*inv[i]%P;
    }
    void dfs(int x)
    {
        siz[x]=1;
        if((x<<1)<=n)dfs(x<<1),siz[x]+=siz[x<<1];
        if((x<<1|1)<=n)dfs(x<<1|1),siz[x]+=siz[x<<1|1];
    }
    LL C(LL x,LL y)
    {
        if(x<y)return 0;
        if(x<P&&y<P)return ((fac[x]*inv[y])%P*inv[x-y])%P;
        return C(x%P,y%P)*C(x/P,y/P);
    }
    int solve(int x)
    {
        if((x<<1)>n||(x<<1|1)>n)return 1;
        return ((C(siz[x]-1,siz[x<<1])*solve(x<<1))%P*solve(x<<1|1))%P;
    }
    int main()
    {
        scanf("%d%d",&n,&P);
        init(),dfs(1);
        printf("%d
    ",solve(1));
        return 0;
    }
  • 相关阅读:
    软件需求阅读笔记02
    软件需求阅读笔记01
    搜狗输入法
    冲刺周之后感想
    典型用户分析和场景
    四则运算
    学习总结
    2019年春阅读笔记5——对开源的认知
    2019年春阅读笔记4——分布式消息系统的现状、挑战与未来
    2019年春阅读笔记3——数据库集群方案
  • 原文地址:https://www.cnblogs.com/Zars19/p/7002034.html
Copyright © 2011-2022 走看看