BZOJ2111: [ZJOI2010] Counting permutations - problem solving

https://www.lydsy.com/JudgeOnline/problem.php?id=2111

https://www.luogu.org/problemnew/show/P2606#sub

A permutation P1,P2...,Pn of 1,2,...,N is said to be Magic if and only if 2<=i<=N, Pi>Pi/2. Calculate 1, 2, . How many of the permutations of ..N are Magic, the answer may be very large, and only the value after modulo P can be output

After drawing a binary tree, it is easy to find that this is a small root heap.

So it becomes the number of small root heaps that meet the conditions.

Obviously, the root can only put the current minimum number, and then assign the left subtree the size of the left subtree, and the right subtree is the same.

So there is f[i]=C(i-1,l)*f[l]*f[r].

In addition, this question card is the log of the fast power, so preprocessing.

#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+5;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch=='-';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
int lg[N],f[N],inv[N],fac[N];
int qpow(ll k,int n,int p){
    int ans=1;
    while(n){
    if(n&1)ans=(ll)ans*k%p;
    k=(ll)k*k%p;n>>=1;
    }
    return ans;
}
int C(int n,int m,int p){
    if(m>n)return 0;
    if(m==n)return 1;
    return (ll)fac[n]*inv[m]%p*inv[n-m]%p;
}
int lucas(int n,int m,int p){
    int ans=1;
    while(n&&m&&ans){
    ans=(ll)ans*C(n%p,m%p,p)%p;
    n/=p,m/=p;
    }
    return ans;
}
inline int lsize(int n){
    int c=lg[n]+1;
    if(c==1)return 0;
    int t=n-(1<<c-1)+1;
    return (1<<c-2)-1+min((1<<c-1>>1),t);
}    
int main(){
    int n=read(),p=read();
    
    lg[1]=0;fac[1]=1;
    for(int i=2;i<=n;i++){
    lg[i] =lg[i- 1 ];
    if (( 1 <<lg[i]+ 1 )==i)lg[i]++ ;
    fac[i]=(ll)fac[i-1]*i%p;
    }
    
    int mx = min (p- 1 , n);
    inv[mx]=qpow(fac[mx],p-2,p);
    for(int i=mx-1;i>=0;i--)inv[i]=(ll)inv[i+1]*(i+1)%p;
    
    f[1]=f[2]=1;
    for(int i=3;i<=n;i++){
    int l=lsize(i);
    f[i]=(ll)lucas(i-1,l,p)*f[l]%p*f[i-l-1]%p;
    }
    printf("%d\n",f[n]);
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

+ Author of this article: luyouqi233. +

+Welcome to my blog: http://www.cnblogs.com/luyouqi233/ +

+++++++++++++++++++++++++++++++++++++++++++

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325065780&siteId=291194637