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;
    }
    
  • 相关阅读:
    JavaScript
    94.Binary Tree Inorder Traversal
    144.Binary Tree Preorder Traversal
    106.Construct Binary Tree from Inorder and Postorder Traversal
    105.Construct Binary Tree from Preorder and Inorder Traversal
    90.Subsets II
    78.Subsets
    83.Merge Sorted Array
    80.Remove Duplicates from Sorted Array II
    79.Word Search
  • 原文地址:https://www.cnblogs.com/Chtholly/p/11687740.html
Copyright © 2011-2022 走看看