# BZOJ2111：[ZJOI2010]排列计数——题解

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

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

#include<cstdio>
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N=1e6+5;
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(){

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;
}

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

+本文作者：luyouqi233。 　　　　　　　　　　　　　　+

+欢迎访问我的博客：http://www.cnblogs.com/luyouqi233/ +

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

posted @ 2018-04-29 11:26  luyouqi233  阅读(160)  评论(0编辑  收藏  举报