zoukankan      html  css  js  c++  java
  • [ZJOI2010]排列计数

    题意

    求1~n的全排列(P_i)的个数,满足对于(igeq 2),有(P_i > P_{i/2})

    思路

    随手画个图就可以发现问题是求大小为(n)的小根堆的个数

    由于左右子树互不影响,直接DP即可,设(dp_{i})表示以(i)为根的小根堆的个数,有(dp_i = dp_{i*2} * dp_{i*2+1} * C(size_i - 1 , size_{i*2}))

    注意本题模数可能小于(n),所以要用(Lucas)定理求组合数

    Code

    #include<bits/stdc++.h>
    #define N 2000005
    #define Min(x,y) ((x)<(y)?(x):(y))
    using namespace std;
    typedef long long ll;
    int n,size[N];
    ll mod;
    ll jc[N],inv[N],dp[N];
    ll quickpow(ll a,ll b)
    {
    	ll ret=1;
    	while(b)
    	{
    		if(b&1) ret=ret*a%mod;
    		a=a*a%mod;
    		b>>=1;
    	}
    	return ret;
    }
    void init()
    {
    	jc[0]=1;
    	int t=Min(n,mod-1);
    	for(int i=1;i<=t;++i) jc[i]=jc[i-1]*i%mod;
    	inv[t]=quickpow(jc[t],mod-2);
    	for(int i=t-1;i>=0;--i) inv[i]=inv[i+1]*(i+1)%mod;
    }
    ll C(int n,int m) {return n>=m ? jc[n]*inv[m]%mod*inv[n-m]%mod : 0;}
    ll lucas(int n,int m)
    {
    	if(!m) return 1;
    	return C(n%mod,m%mod)*lucas(n/mod,m/mod)%mod;
    }
    void DFS(int rt)
    {
    	if(rt>n) return;
    	size[rt]=1;
    	DFS(rt<<1); DFS(rt<<1|1);
    	size[rt]+=size[rt<<1]+size[rt<<1|1];
    }
    void dfs(int rt)
    {
    	if(rt>n) return (void)(dp[rt]=1);
    	dfs(rt<<1); dfs(rt<<1|1);
    	dp[rt]=lucas(size[rt]-1,size[rt<<1])*dp[rt<<1]%mod*dp[rt<<1|1]%mod;
    }
    
    int main()
    {
    	cin>>n>>mod;
    	init();
    	DFS(1);
    	dfs(1);
    	cout<<dp[1]<<endl;
    	return 0;
    }
    
  • 相关阅读:
    jquery 知识点
    java基础 知识点
    eclipse使用问题
    java中各种集合的用法和比较
    svn服务器安装
    dbcp连接mysql
    java中分页的实现
    在maven框架下遇到的问题及解决方法
    c++获取系统时间,精确到ms级
    qtcreator.exe已停止工作
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11687740.html
Copyright © 2011-2022 走看看