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

    题意:

    称一个1-n的排列是Magic的,当且仅当$forall i in [2,n],p_i > p_{lfloor frac{i}{2} floor}$。

    求有多少排列是Magic的,答案对m取模。

    $nleq 10^{6},mleq 10^{9}$。

    题解:

    容易发现这是一个完全二叉树的结构,要求每个点权大于父亲点权,求点权分配方案数。

    那么直接dp即可,令$f_u$为以u为根的子树的方案数,则有$f_u = f_{2u} imes f_{2u+1} imes {{siz_u -1}choose{siz_{2u}}}$。

    注意数据范围并不满足$m>n$,所以需要$Lucas$定理算组合数。

    复杂度$O(n)$。

    套路:

    • 组合数取模时:系数不一定小于模数$ ightarrow$Lucas定理。

    代码:

    #include<bits/stdc++.h>
    #define maxn 1000005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register ll
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
    
    using namespace std;
    ll n,mod,siz[maxn],dp[maxn],fac[maxn],ifac[maxn];
    
    inline ll read(){
        ll x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    inline ll power(ll a,ll b){
        ll ans=1;
        while(b){
            if(b&1) ans=ans*a%mod;
            a=a*a%mod,b>>=1;
        }
        return ans;
    }
    inline ll C(ll n,ll m){
        if(n>=mod) return C(n%mod,m%mod)*C(n/mod,m/mod)%mod;
        else return fac[n]*ifac[m]%mod*ifac[n-m]%mod;
    }
    
    inline void dfs1(ll x){
        siz[x]=1;
        if((x<<1)<=n) dfs1(x<<1),siz[x]+=siz[x<<1];
        if((x<<1|1)<=n) dfs1(x<<1|1),siz[x]+=siz[x<<1|1];
    }
    
    inline void dfs2(ll x){
        if((x<<1)<=n && (x<<1|1)<=n){
            dfs2(x<<1),dfs2(x<<1|1);
            dp[x]=dp[x<<1]*dp[x<<1|1]%mod*C(siz[x]-1,siz[x<<1])%mod;
        }
        else if((x<<1)<=n) dfs2(x<<1),dp[x]=dp[x<<1];
        else if((x<<1|1)<=n) dfs2(x<<1|1),dp[x]=dp[x<<1|1];
        else dp[x]=1;
    }
    
    int main(){
        n=read(),mod=read();
        ll mx=min(n,mod-1); fac[0]=1; 
        for(ll i=1;i<=mx;i++) fac[i]=fac[i-1]*i%mod;
        ifac[mx]=power(fac[mx],mod-2);
        for(ll i=mx-1;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
        dfs1(1),dfs2(1);
        printf("%lld
    ",dp[1]);
        return 0;
    }
    排列计数
  • 相关阅读:
    UML用例图总结
    项目管理心得:一个项目经理的个人体会、经验总结
    UML类图符号简介
    C++中栈和堆上建立对象的区别
    Win32 API
    Python
    remove extra kernel
    Create short cut
    Set Form Position
    Get folder
  • 原文地址:https://www.cnblogs.com/YSFAC/p/13228940.html
Copyright © 2011-2022 走看看