题目梗概
求[1,n]有多少个排列满足 Pi>Pi/2
解题思路
不难发现排列构成一个小根堆,因此树形可以确定。
然后用 f[i] 表示以第i个节点为根的方案数。
转移方程不难得出。
最主要的是这题虽然P很大但是依然要用Lucas,为什么呢?
因为处理n的阶乘时到后面%P会变成0,所以要限制阶乘的范围。
WA了5发才反应过来。
#include<cstdio>
#include<algorithm>
#define LL long long
using namespace std;
const int maxn=1000005;
int n,tt,s[2*maxn];
LL ji[maxn],f[maxn];
int qsm(LL w,int b){
LL num=1;
while(b){
if (b%2==1) num=num*w%tt;
w=w*w%tt;
b>>=1;
}
return num;
}
int c(int x,int y){if (x>y) return 0;return ji[y]*qsm(ji[x]*ji[y-x]%tt,tt-2)%tt;}
int Q(int x,int y){int num=1;while(y) num=(LL)num*c(x%tt,y%tt)%tt,x/=tt,y/=tt;return num;}
int main(){
freopen("exam.in","r",stdin);
freopen("exam.out","w",stdout);
scanf("%d%d",&n,&tt);
if (tt==1) return printf("0\n"),0;
ji[0]=1;for (int i=1;i<=min(n,tt-1);i++) ji[i]=ji[i-1]*i%tt;
for (int i=n;i>=1;i--){
s[i]=s[i*2+1]+s[i*2]+1;
f[i]=Q(s[i*2],s[i]-1);
if (i*2+1<=n) f[i]=f[i]*f[i*2+1]%tt;
if (i*2<=n) f[i]=f[i]*f[i*2]%tt;
}
printf("%lld\n",f[1]);
return 0;
}