[ZJOI2010]排列計數,數位Dp
阿新 • • 發佈:2018-11-02
正題
首先,我們先轉化問題,要求,就相當於要求。
那麼這就像當與一棵n個節點的完全二叉樹,那麼我們統計一下每棵子樹的大小,然後下去更新算一下組合數就可以了。
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> using namespace std; int n; long long p; int l[1000010]; int tot[1000010]; long long fac[1000010],fav[1000010]; void dfs(int x){ tot[x]=1; if(x*2<=n) { dfs(x*2); tot[x]+=tot[x*2]; l[x]=tot[x*2]; } if(x*2+1<=n) { dfs(x*2+1); tot[x]+=tot[x*2+1]; } } long long C(int x,int y){ return fac[x]*fav[x-y]%p*fav[y]%p; } long long F(int x){ if(x*2+1<=n) return F(x*2)*F(x*2+1)%p*C(tot[x]-1,l[x])%p; else if(x*2<=n) return F(x*2); else return 1; } long long ksm(long long x,long long t){ long long tot=1; while(t>0){ if(t%2==1){ tot*=x; tot%=p; } t/=2; x*=x; x%=p; } return tot; } long long inv(long long x){ return ksm(x,p-2); } int main(){ scanf("%d %lld",&n,&p); fac[0]=1; for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i%p; fav[n]=inv(fac[n]); for(int i=n-1;i>=1;i--) fav[i]=fav[i+1]*(i+1)%p; dfs(1); printf("%lld\n",F(1)); }