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;
    }
  • 相关阅读:
    学习第五天
    第四天学习
    学习第三天
    学校键盘键位设置
    学习第二天
    fatal error C1902: 程序数据库管理器不匹配;请检查安装解决
    ffmpeg遇到inttypes.h和UINT64_C
    <ZZ>linux yum命令详解
    <ZZ>Linux rpm 命令参数使用详解[介绍和应用]
    转:Windows下WSH/JS实现SVN服务器钩子脚本阻止提交空日志信息和垃圾文件
  • 原文地址:https://www.cnblogs.com/Rorschach-XR/p/11106878.html
Copyright © 2011-2022 走看看