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

题目梗概

求[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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值