BZOJ2111 ZJOI2010排列计数
根据Pi>Pi/2可以看出来这是一个二叉树
所以我们可以用树形DP的思想
f[i]=f[i<<1]*f[i<<1|1]*C(s[i]-1,s[i<<1]),s是子树大小
然后求组合数可以用卢卡斯定理
BZ上加强数据后我那个线性求n!逆元就挂掉了,于是就直接算了。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=2e6+5; ll f[N<<1],fac[N],inv[N],s[N<<1]; ll n,mod; ll qmod(ll a,ll b) { ll ans=1; while(b) { if(b&1)ans=ans*a%mod; a=a*a%mod;b>>=1; } return ans; } ll C(ll a,ll b) { if(a<b)return 0; if(a<mod&&b<mod)return fac[a]*qmod(fac[b]*fac[a-b]%mod,mod-2)%mod; return C(a/mod,b/mod)*C(a%mod,b%mod)%mod; } int main() { scanf("%lld%lld",&n,&mod); fac[0]=1; for(int i=1;i<=n;++i)fac[i]=i*fac[i-1]%mod; for(int i=n;i;--i) { s[i]=s[i<<1]+s[(i<<1)|1]+1;f[i]=1; if((i<<1)<=n)f[i]=f[i]*f[i<<1]%mod; if((i<<1|1)<=n)f[i]=f[i]*f[i<<1|1]%mod; f[i]=f[i]*C(s[i]-1,s[i<<1])%mod; } printf("%lld",f[1]); return 0; }
生命中真正重要的不是你遭遇了什么,而是你记住了哪些事,又是如何铭记的。