zoukankan      html  css  js  c++  java
  • P4370 [Code+#4]组合数问题2

    题目要求当\(0\leq a\leq b\leq n\)时,\(k\)\(\tbinom{b}{a}\)的和的最大值

    观察杨辉三角形,可以发现,最大的\(\tbinom{b}{a}\),为\(\tbinom{n}{\frac{n}{2}}\)
    还可以知道,除了当前最大的组合数以外,可能最大的,是它周围的四个
    即如果当前确定的最大组合数为\(\tbinom{n}{m}\),则接下来有可能成为最大的数是:\(\tbinom{n}{m-1},\tbinom{n}{m+1},\tbinom{n-1}{m-1},\tbinom{n-1}{m}\)
    可以写一个杨辉三角理解一下
    然后可以用一个优先队列维护,每次取出当前的最大值
    那么如何比较两个组合数的大小?写高精算出来(bushi
    用一个神奇的方法:取\(\log\)
    \(\log ab=\log a+\log b,\log\frac{a}{b}=\log a-\log b\)
    则可以先预处理出\(\log x!,0\leq x\leq n\),然后再算组合数\(\tbinom{n}{m}=\log n!-\log m!-\log (n-m)!\)
    然后在堆中比较\(\log\)的大小
    然后我愉快的把堆写炸了
    算组合数就是预处理阶乘和阶乘逆元就行了
    一定要记得判断当前最大的组合数周围的那四个数是否存在,具体见代码

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<iomanip>
    #include<cstring>
    #include<map>
    #define reg register
    #define EN std::puts("")
    #define LL long long
    inline int read(){
    	int x=0,y=1;
    	char c=std::getchar();
    	while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();}
    	while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();}
    	return y?x:-x;
    }
    int n,k;
    const LL mod=1e9+7;
    struct data{
    	int n,m;
    	double Log;
    }dui[500006];
    int size;
    LL fac[1000006],inv[1000006];
    double Log[1000006];
    std::map<std::pair<int,int>,bool>map;
    inline void push(data x){
    	map[std::make_pair(x.n,x.m)]=1;
    	dui[++size]=x;
    	reg int i=size,fa;
    	while(i>1){
    		fa=i>>1;
    		if(dui[fa].Log>dui[i].Log) break;
    		std::swap(dui[fa],dui[i]);i=fa;
    	}
    }
    inline data pop(){
    	data ret=dui[1];dui[1]=dui[size--];
    	reg int i=1,ls,rs;
    	while((ls=i<<1)<=size){
    		rs=ls|1;
    		if(rs<=size&&dui[rs].Log>dui[ls].Log) ls=rs;
    		if(dui[i].Log>dui[ls].Log) break;
    		std::swap(dui[i],dui[ls]);i=ls;
    	}
    	return ret;
    }
    inline LL power(LL a,LL b){
    	LL ret=1;
    	while(b){
    		if(b&1) ret=(ret*a)%mod;
    		a=(a*a)%mod;b>>=1;
    	}
    	return ret;
    }
    inline void pre(){
    	fac[0]=inv[0]=1;
    	for(reg int i=1;i<=n;i++) fac[i]=(fac[i-1]*i)%mod;
    	inv[n]=power(fac[n],mod-2);
    	for(reg int i=n-1;i;i--) inv[i]=(inv[i+1]*(i+1))%mod;
    	for(reg int i=1;i<=n;i++) Log[i]=log(i)+Log[i-1];
    }
    inline double getLog(int nn,int mm){
    	return Log[nn]-Log[mm]-Log[nn-mm];
    }
    int main(){
    	n=read();k=read();
    	pre();
    	push((data){n,n/2,getLog(n,n/2)});
    	reg data now;
    	reg LL ans=0;
    	std::pair<int,int>tmp;
    	reg int nn,mm;
    	while(k--){
    		now=pop();
    		nn=now.n;mm=now.m;
    		ans+=((fac[nn]*inv[mm])%mod*inv[nn-mm])%mod;
    		ans%=mod;
    //			std::printf("%d %d %d\n",ans,nn,mm);
    		if(mm-1>=0){
    			tmp=std::make_pair(nn,mm-1);
    			if(!map[tmp])
    				push((data){nn,mm-1,getLog(nn,mm-1)});
    		}
    		if(mm+1<=nn){
    			tmp=std::make_pair(nn,mm+1);
    			if(!map[tmp])
    				push((data){nn,mm+1,getLog(nn,mm+1)});
    		}
    		if(mm-1>=0&&nn-1>=0){
    			tmp=std::make_pair(nn-1,mm-1);
    			if(!map[tmp])
    				push((data){nn-1,mm-1,getLog(nn-1,mm-1)});
    		}
    		if(nn-1>=mm){
    			tmp=std::make_pair(nn-1,mm);
    			if(!map[tmp])
    				push((data){nn-1,mm,getLog(nn-1,mm)});
    		}
    	}
    	std::printf("%lld",ans);
    	return 0;
    }
    
  • 相关阅读:
    4个小时实现一个HTML5音乐播放器
    一款好看+极简到不行的HTML5音乐播放器-skPlayer
    操纵浏览器的历史记录
    基于jQuery查找dom的多种方式性能问题
    你真的了解console吗?
    关于overflow:hidden和bfc
    jQuery插件开发
    深入浅出jsonp
    jQuery.extend 函数详解
    [转] Hibernate一级缓存、二级缓存
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/12527254.html
Copyright © 2011-2022 走看看