[数学杂题]BZOJ 2111—— [ZJOI2010]Perm 排列计数

来源:互联网 发布:mac软件下载网站排名 编辑:程序博客网 时间:2024/05/19 04:25

题目梗概

求[1,n]有多少个排列满足Pi>Pi/2

解题思路

不难发现排列构成一个小根堆,因此树形可以确定。

然后用f[i]表示以第i个节点为根的方案数。

转移方程不难得出。

最主要的是这题虽然P很大但是依然要用Lucas,为什么呢?

因为处理n的阶乘时到后面%P会变成0,所以要限制阶乘的范围。

WA了5发才反应过来。

#include<cstdio>#include<algorithm>#define LL long longusing 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;}
阅读全文
0 0
原创粉丝点击