• [BZOJ2111] [ZJOI2010]Perm 排列计数


    [BZOJ2111] [ZJOI2010]Perm 排列计数

    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,?, n的排列中, Magic排列的个数模 p的值。

    Sample Input

    20 23

    Sample Output

    16

    HINT

    (1leq nleq 10^6)

    试题分析

    不难发现这是一棵大根堆,直接dp就好了。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<queue>
    #include<stack>
    #include<algorithm>
    using namespace std;
      
    #define LL long long
      
    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;
    }
    const LL MAXN=1100001;
    const LL INF=999999;
      
    LL N,P; LL fac[MAXN+1];
    LL c[MAXN+1];
      
    inline LL Pow(LL a,LL b){
        LL ans=1LL;
        while(b){
            if(b&1) ans=ans*a%P;
            a=a*a%P; b>>=1;
        } return ans;
    }
    inline LL Lucas(LL N,LL M){
        if (M>N) return 0; if(M==N) return 1;
        if (N<P&&M<P) return (fac[N]*Pow(fac[N-M],P-2)%P*Pow(fac[M],P-2)%P)%P;
        else return Lucas(N/P,M/P)*Lucas(N%P,M%P)%P;
    }
    inline LL dp(LL k){
        if(k==1) return 1; if(!k) return 1; --k;
        LL l=1,r=19,cnt=0; while(l<=r){
            LL mid=(l+r)>>1;
            if(c[mid]<=k&&k-c[mid]>=c[mid-1]) cnt=mid,l=mid+1;
            else r=mid-1;
        }LL tmp=cnt-1; if(2*c[cnt]<=k) tmp++; LL L,R;
        if(tmp==cnt-1) R=k-c[cnt],L=c[cnt]; else L=c[cnt]+k-2*c[cnt],R=k-L;
        return Lucas(k,L)*dp(L)%P*dp(R)%P;
    }
      
    int main(){
        //freopen(".in","r",stdin);
        //freopen(".out","w",stdout);
        N=read(),P=read(); fac[1]=1;
        for(LL i=2;i<=N;i++) fac[i]=fac[i-1]*i%P;
        for(LL i=1;i<=19;i++) c[i]=c[i-1]+(1LL<<(i-1));
        printf("%lld
    ",dp(N));
        return 0;
    }
    
    
  • 相关阅读:
    SVN服务器搭建(一)
    排序算法二:冒泡排序
    【LeetCode】136. Single Number
    【LeetCode】217. Contains Duplicate
    【LeetCode】189. Rotate Array
    【LeetCode】122. Best Time to Buy and Sell Stock II
    【LeetCode】26. Remove Duplicates from Sorted Array
    【LeetCode】20. Valid Parentheses
    【LeetCode】680. Valid Palindrome II
    【LeetCode】345. Reverse Vowels of a String
  • 原文地址:https://www.cnblogs.com/wxjor/p/9540498.html
Copyright © 2020-2023  润新知