• 题解 P2606 【[ZJOI2010]排列计数】


    题目链接

    Solution [ZJOI2010]排列计数

    题目大意:求 (1-n) 的排列 (p) 中,有多少个排列满足 (forall iin [2,n],p_i > p_{lfloorfrac{i}{2} floor}),对给定质数 (m) 取模。


    分析:

    (p_i > p_{lfloorfrac{i}{2} floor}),反过来 (forall x,p_x<p_{2x},p_{2x+1}),那么问题变成一棵 (n) 个节点的完全二叉树,将数 (1-n) 分配给每一个节点,使得每个父节点都比它两个子节点权值要小的方案数。

    进一步,我们不关心数究竟是啥,我们只关心它们之间的相对大小关系。

    (siz[u]) 表示以 (u) 为根的子树大小,(f[u]) 表示将 (siz[u]) 个互不相同的数分配给以 (u) 为根的子树的合法方案数。记 (ls,rs) 为左右儿子。

    那么 (f[u]=f[ls]cdot f[rs] cdot inom{siz[ls]+siz[rs]}{siz[ls]})

    坑点在于,(n) 有可能比 (m) 大,此时需要使用 ( ext{Lucas}) 定理

    #include <cstdio>
    using namespace std;
    const int maxn = 1e6 + 100;
    int n,mod;
    inline int add(const int a,const int b){return (a + b) % mod;}
    inline int mul(const int a,const int b){return (1ll * a * b) % mod;}
    inline int qpow(int base,int b){
    	int res = 1;
    	while(b){
    		if(b & 1)res = mul(res,base);
    		base = mul(base,base);
    		b >>= 1;
    	}
    	return res;
    }
    inline int inv(const int x){return qpow(x,mod - 2);}
    int fac[maxn];
    inline void init(){
    	fac[0] = 1;
    	for(int i = 1;i <= n;i++)fac[i] = mul(fac[i - 1],i);
    }
    extern inline int C(const int n,const int m);
    inline int lucas(const int n,const int m){
    	if(n < mod)return C(n,m);
    	return mul(C(n / mod,m / mod),C(n % mod,m % mod));
    }
    inline int C(const int n,const int m){return n < mod ? mul(fac[n],inv(mul(fac[m],fac[n - m]))) : lucas(n,m);}
    int f[maxn << 2],siz[maxn << 2];
    #define ls (u << 1)
    #define rs (u << 1 | 1)
    inline void dp(const int u){
    	f[u] = 1;
    	if(u < 1 || u > n)return;
    	siz[u] = 1;
    	dp(ls);
    	dp(rs);
    	siz[u] += siz[ls];
    	siz[u] += siz[rs];
    	f[u] = mul(
    		C(siz[u] - 1,siz[ls]),
    		mul(f[ls],f[rs])
    	);
    }
    #undef ls
    #undef rs
    int main(){
    	scanf("%d %d",&n,&mod);
    	init();
    	dp(1);
    	printf("%d
    ",f[1]);
    	return 0;
    }
    
  • 相关阅读:
    c++ socket发送数据时,sendData = char * string 导致的乱码问题
    c++ sprintf() 用法
    c++ 将float 类型转换成string 类型
    c++中 string类型 转为 char []类型
    c++ 去掉所有空格及换行符
    c++处理字符串string.find()与string::npos
    C1010 unexpected end of file while looking for precompiled header. Did you forget to add '#include "stdafx.h"' to your source
    C++ socket bind() 函数绑定错误
    windows 全局安装 composer
    VMware Tools (ubuntu系统)安装详细过程与使用
  • 原文地址:https://www.cnblogs.com/colazcy/p/14133304.html
Copyright © 2020-2023  润新知