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

    Description

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

    Input

    输入文件的第一行包含两个整数 n和p,含义如上所述。

    Output

    输出文件中仅包含一个整数,表示计算1,2,⋯, ���的排列中, Magic排列的个数模 p的值。

    Sample Input

    20 23

    Sample Output

    16

    HINT

    100%的数据中,1 ≤ ��� N ≤ 106, P��� ≤ 10^9,p是一个质数。 数据有所加强

    如图

    把问题转化为

    用1--n的数 组成一个完全二叉树使之满足小根堆性质的方案数

    考虑dp

    设i点的子结点数量为size[i]

    则$dp[i]=C(s[i]-1,s[i*2])*f[i*2]*f[i*2+1]$

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    ll n,p;
    ll dp[2000005],size[2000005],fac[1000005];
    ll qpow(ll a,ll b,ll mod)
    {
        ll res=1;
        a=a%mod;
        while(b)
        {
            if(b&1)res=(res*a)%mod;
            b=b>>1;
            a=(a*a)%mod;
        }
        return res;
    }
    ll C(ll x,ll y,ll mod)
    {
        if(x<y)return 0;
        return fac[x]*qpow(fac[y],p-2,p)%p*qpow(fac[x-y],p-2,p)%p;
    }
    ll lucas(ll x,ll y,ll p)
    {
        if(!y)return 1;
        return C(x%p,y%p,p)*lucas(x/p,y/p,p)%p;
    }
    int main()
    {
        scanf("%lld%lld",&n,&p);
        fac[0]=fac[1]=1;
        for(int i=2;i<=n;i++)fac[i]=fac[i-1]*i%p;
        for(int i=n;i;i--)
        {
            size[i]=size[i<<1]+size[i<<1|1]+1;
            dp[i]=lucas(size[i]-1,size[i<<1],p);
            if(n>=(i<<1))dp[i]=dp[i]*dp[i<<1]%p;
            if(n>=(i<<1|1))dp[i]=dp[i]*dp[i<<1|1]%p;
        }
        //for(int i=1;i<=n;i++)cout<<dp[i]<<endl;
        cout<<dp[1]<<endl;
        return 0;
    }
  • 相关阅读:
    09-排序1 排序
    06-图3 六度空间
    06-图2 Saving James Bond
    06-图1 List Components
    04-树5 Complete Binary Search Tree
    03-树2 Tree Traversals Again
    PAT 05-树8 Huffman Codes
    Egret引擎的visible两次开关闭问题
    Egret的项目笔记(一)
    Egret屏幕适配【转】
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11106878.html
Copyright © 2011-2022 走看看