zoukankan      html  css  js  c++  java
  • 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[maxn];
    Lint Ksm(Lint a,int p){
    	Lint ret=1;
    	for(;p;p>>=1,a=a*a%mm){
    		if(p&1)ret=ret*a%mm;
    	}
    	return ret;
    }
    Lint Inv(Lint x){
    	return Ksm(x,mm-2);
    }
    Lint C(int n,int m){
    	int tmp=h[n]-h[m]-h[n-m];
    	if(tmp)return 0;
    	return f[n]*Inv(f[m])%mm*Inv(f[n-m])%mm;
    }
    
    int t=0;
    int main(){
    	scanf("%d%d",&n,&mm);
    	f[0]=1;h[0]=0;
    	for(int i=1;i<=n;++i){
    		int x=i;h[i]=h[i-1];
    		while(x%mm==0){
    			x/=mm;++h[i];
    		}
    		f[i]=f[i-1]*x%mm;
    	}
    	
    	g[0]=g[1]=1;
    	for(int i=2;i<=n;++i){
    		while((1<<(t+1))-1<=i)++t;
    		int res=i-((1<<t)-1);
    		if(res>=(1<<(t-1))){
    			g[i]=C(i-1,(1<<t)-1)*g[(1<<t)-1]%mm*g[i-(1<<t)]%mm;
    		}else{
    			g[i]=C(i-1,(1<<(t-1))+res-1)*g[(1<<(t-1))+res-1]%mm*g[(1<<(t-1))-1]%mm;
    		}
    	}
    	cout<<g[n]<<endl;
    }
    

      

    自己还是太辣鸡了
  • 相关阅读:
    左边菜单导航
    css3实现轮播
    js-统计选项个数
    空间评论。回复。点赞功能
    简单的购物车功能
    字符串常用的几种方法
    React,js实现分页的案列
    python2的cgi程序
    开发环境和工具
    github入门
  • 原文地址:https://www.cnblogs.com/zzyer/p/8455501.html
Copyright © 2011-2022 走看看