bzoj 2111: [ZJOI2010]Perm 排列计数 Lucas

code:

#include <bits/stdc++.h>
#define N 2000004
#define LL long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
LL mod;
LL fac[N],inv[N],f[N],size[N];
LL qpow(LL x,LL y)
{
    LL tmp=1ll;
    for(;y;y>>=1,x=x*x%mod) if(y&1)    tmp=tmp*x%mod;
    return tmp;
}
LL C(int n, int m)
{
    if (n<m)   return 0ll;
    if (n<mod && m<mod) return   fac[n]*inv[m]%mod*inv[n-m]%mod;
    return   C(n/mod,m/mod)*C(n%mod,m%mod);
}
int main()
{
    // setIO("input");
    int i,j,n;
    scanf("%d%lld",&n,&mod);
    fac[0]=inv[0]=1ll;
    for(i=1;i<=n;++i)     fac[i]=fac[i-1]*1ll*i%mod,inv[i]=qpow(fac[i],mod-2);
    for(i=0;i<=2*n;++i)   f[i]=1ll;
    for(i=n;i>0;i--){
        size[i]++;
        size[i/2]+=size[i];
    }
    for(i=n;i>=1;--i)
    {
        if(size[i]==1) continue;
        else
        {
            f[i]=C(size[i]-1,size[i*2])*f[i*2]%mod*f[i*2+1]%mod;
            //          printf("%d %d\n",size[i]-1,size[i*2]);
            // printf("%lld %lld %lld\n",C(i-1,size[i*2]),f[i*2],f[i*2+1]);
            // printf("%lld\n",f[i]);
        }
    }
    printf("%lld\n",f[1]);
    return 0;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/11768745.html

时间: 2024-08-04 14:48:41

bzoj 2111: [ZJOI2010]Perm 排列计数 Lucas的相关文章

bzoj 2111: [ZJOI2010]Perm 排列计数 (dp+卢卡斯定理)

bzoj 2111: [ZJOI2010]Perm 排列计数 1 ≤ N ≤ 10^6, P≤ 10^9 题意:求1~N的排列有多少种小根堆 1: #include<cstdio> 2: using namespace std; 3: const int N = 1e6+5; 4: typedef long long LL; 5: LL m, p, T, x, y, F[N]; 6: LL n, size[N<<1]; 7: LL f[N]; 8: LL inv(LL t, LL

bzoj 2111 [ZJOI2010]Perm 排列计数(DP+lucas定理)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2111 [题意] 给定n,问1..n的排列中有多少个可以构成小根堆. [思路] 设f[i]为以i为根的方案数,设l为左子树大小r为右子树大小,则有: f[i]=C(i-1,l)*f[l]*f[r] 因为是个堆,所以子树大小都是确定的,可以直接递推得到. 其中C(n,m) nm比较大,可以用lucas定理求. 模型建立的重要性可知一二... [代码] 1 #include<cstdio>

BZOJ 2111 ZJOI2010 Perm 排列计数 组合数学+Lucas定理

题目大意:求1~n的排列能组成多少种小根堆 考虑一个1~i的排列所构成的堆,l为左儿子大小,r为右儿子的大小 那么1一定是堆顶 左儿子和右儿子分别是一个堆 显然如果选出l个数给左儿子 那么左儿子的方案数显然是f[l],右儿子的方案数为f[r] 于是有f[i]=C(i-1,l)*f[l]*f[r] 于是我们线性筛处理出阶乘和阶乘的逆元 代入即可得到WA 原因是这题n可以大于p 此时要用到Lucas定理 坑死了 #include <cstdio> #include <cstring>

BZOJ 2111 [ZJOI2010]Perm 排列计数

题解:发现问题的本质,即堆的个数 动态规划一下 f[i]表示前i个元素形成的堆的个数 第i个元素为根,左右子树又是两个堆 注意:逆元存在条件 #include<iostream> #include<cstdio> #include<cstring> using namespace std; typedef long long Lint; const int maxn=1000009; int n,mm; Lint f[maxn]; int h[maxn]; Lint g

组合数学+lucas定理+逆元 BZOJ2111 [ZJOI2010]Perm 排列计数

2111: [ZJOI2010]Perm 排列计数 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 2118  Solved: 563[Submit][Status][Discuss] Description 称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很大,只能输出模P以后的值 Input 输入文件的第一行包含两个

【BZOJ2111】[ZJOI2010]Perm 排列计数 组合数

[BZOJ2111][ZJOI2010]Perm 排列计数 Description 称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很大,只能输出模P以后的值 Input 输入文件的第一行包含两个整数 n和p,含义如上所述. Output 输出文件中仅包含一个整数,表示计算1,2,?,的排列中, Magic排列的个数模 p的值. Sample Input 20 23

ZJOI2010 Perm 排列计数

[ZJOI2010]Perm 排列计数 时间限制: 1 Sec  内存限制: 259 MB 题目描述 称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很大,只能输出模P以后的值 输入 输入文件的第一行包含两个整数 n和p,含义如上所述. 输出 输出文件中仅包含一个整数,表示计算1,2,?, ???的排列中, Magic排列的个数模 p的值. 样例输入 20 23 样例

【bzoj2111】[ZJOI2010]Perm 排列计数 dp+Lucas定理

题目描述 称一个1,2,...,N的排列P1,P2...,Pn是Mogic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Mogic的,答案可能很大,只能输出模P以后的值 输入 输入文件的第一行包含两个整数 n和p,含义如上所述. 输出 输出文件中仅包含一个整数,表示计算1,2,?, n的排列中, Mogic排列的个数模 p的值. 样例输入 20 23 样例输出 16 题解 dp+Lucas定理 题目显然小根堆,考虑怎么求以一个节点为根的方案数.根肯定

BZOJ2111: [ZJOI2010]Perm 排列计数

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2111 题意:一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很大,只能输出模P以后的值 题解:注意到形成一个树状结构,如果不妨设f[i]为i所在子树分配s[i]个节点的方案数. 那么有递推式:f[i]=f[i<<1]*f[i<<1|1]*c(