正题
题目链接:
https://www.lydsy.com/JudgeOnline/problem.php?id=2111
https://www.luogu.org/problem/P2606
题目大意
长为nnn的序列PPP,然后要求Pi>P⌊i2⌋P_i>P_{\lfloor \frac{i}{2}\rfloor}Pi>P⌊2i⌋。求排列个数。
解题思路
若用iii连向⌊i2⌋\lfloor \frac{i}{2}\rfloor⌊2i⌋,那么这是一棵以111为根的数,然后考虑树形dpdpdp。
我们发现每棵子树满足子节点小于父节点的性质且两棵不包含的子树互不关联,所以我们只需要分配编号即可
也就是fi=f2∗i∗f2∗i+1∗Csizei−1size2∗if_{i}=f_{2*i}*f_{2*i+1}*C_{size_i-1}^{size_{2*i}}fi=f2∗i∗f2∗i+1∗Csizei−1size2∗i
然后答案就是f1f_1f1。因为在其中fif_ifi可能会大于ppp,所以我们用LucasLucasLucas定理
时间复杂度O(nlogn+min{n,p})O(n\log n+min\{n,p\})O(nlogn+min{n,p})
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=1e6+10;
ll T,n,p,a[N],f[2*N],s[2*N];
ll power(ll x,ll b,ll p)
{ll ans=1;while(b){if(b&1) ans=ans*x%p;x=x*x%p;b>>=1;}return ans;
}
ll C(ll n,ll m,ll p)
{if(m>n) return 0ll;return a[n]*power(a[m],p-2,p)%p*power(a[n-m],p-2,p)%p;
}
ll lucas(ll n,ll m,ll p)
{if(!m) return 1ll;return lucas(n/p,m/p,p)*C(n%p,m%p,p)%p;
}
int main()
{scanf("%lld%lld",&n,&p);a[0]=1;for(ll i=1;i<=min(n,p);i++)a[i]=a[i-1]*i%p;for(ll i=n;i>=1;i--){s[i]=1+s[i*2]+s[i*2+1];if(i*2+1<=n)f[i]=f[i*2]*f[i*2+1]%p*lucas(s[i]-1,s[i*2],p)%p;else if(i*2<=n) f[i]=f[i*2];else f[i]=1; }printf("%lld",f[1]);return 0;
}