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

    题目

    坐标(/2)这种神奇的性质肯定在暗示什么

    基本是完全二叉树了

    又发现(P_{i}<P_{i/2}),于是发现这是一棵小根堆

    题意变成了求满足条件的小根堆有多少个

    考虑一个树形(dp)

    (dp_{i})表示(i)为根的小根堆有几种,(sz_{i})表示这个小根堆的大小,假设当前小根堆就表示(1)(sz[i])这些数

    那么(i)这个节点肯定要填上(1)

    剩下的节点来自左右子树,我们分配一下,就是

    [dp_{ls} imes dp_{rs} imes inom{sz_i-1}{sz_{ls}} ]

    就是先给左子树找好位置,之后剩下的插空填上就好了

    可能需要用(Lucas)

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define LL long long
    #define re register
    #define maxn 1000005
    inline int read() {
    	int x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();
    	while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
    }
    int n;LL mod;
    LL fac[maxn],inv[maxn],dp[maxn];
    int sz[maxn];
    inline LL C(int n,int m) {if(m>n) return 0;return fac[n]*inv[n-m]%mod*inv[m]%mod;}
    inline LL ksm(LL a,int b) {LL S=1;while(b) {if(b&1) S=S*a%mod;b>>=1;a=a*a%mod;}return S;}
    namespace sub1 {
    	inline void solve() {
    		fac[0]=1;for(re int i=1;i<=n;i++) fac[i]=(fac[i-1]*(LL)i)%mod;
    		inv[n]=ksm(fac[n],mod-2);
    		for(re int i=n-1;i>=0;--i) inv[i]=(inv[i+1]*(LL)(i+1))%mod;
    		for(re int i=1;i<=n;i++) sz[i]=1;
    		for(re int i=1;i<=n+1;i++) dp[i]=1;
    		for(re int i=n;i>=1;--i) {
    			sz[i>>1]+=sz[i];
    			if(sz[i]==1) continue;
    			dp[i]=C(sz[i<<1]+sz[i<<1|1],sz[i<<1])*dp[i<<1|1]%mod*dp[i<<1]%mod;
    		}
    		printf("%lld
    ",dp[1]);
    	}
    }
    namespace sub2 {
    	inline LL Lucas(int n,int m) {
    		if(n<mod||m<mod) return C(n,m);
    		return Lucas(n/mod,m/mod)*C(n%mod,m%mod)%mod;
    	}
    	inline void solve() {
    		fac[0]=1;for(re int i=1;i<mod;i++) fac[i]=(fac[i-1]*(LL)i)%mod;
    		inv[mod-1]=ksm(fac[mod-1],mod-2);
    		for(re int i=mod-2;i>=0;--i) inv[i]=(inv[i+1]*(LL)(i+1))%mod;
    		for(re int i=1;i<=n;i++) sz[i]=1;
    		for(re int i=1;i<=n+1;i++) dp[i]=1;
    		for(re int i=n;i>=1;--i) {
    			sz[i>>1]+=sz[i];
    			if(sz[i]==1) continue;
    			dp[i]=Lucas(sz[i<<1]+sz[i<<1|1],sz[i<<1])*dp[i<<1|1]%mod*dp[i<<1]%mod;
    		}
    		printf("%lld
    ",dp[1]);
    	}
    	
    }
    int main() {
    	n=read(),mod=read();
    	if(mod>n) sub1::solve();
    		else sub2::solve();
    	return 0;
    }
    
  • 相关阅读:
    java作业总结1
    Java课程学习感想
    java第二阶段作业小结
    java第一阶段作业小结
    Java课程总结
    第二周期作业总结
    第一次作业周期总结
    Java第二阶段作业总结
    Java第一阶段作业总结
    java最后一阶段总结
  • 原文地址:https://www.cnblogs.com/asuldb/p/10483335.html
Copyright © 2011-2022 走看看