• ●BZOJ 1272 [BeiJingWc2008]Gate Of Babylon


    题链:

    http://www.lydsy.com/JudgeOnline/problem.php?id=1272

    题解:

    容斥,Lucas定理
    本题的容斥考虑类似
    [BZOJ 1042 [HAOI2008]硬币购物]
    ANS = 至少 0 种超级神器超过数量限制的方案数
                  -至少 1 种超级神器超过数量限制的方案数
                 +至少 2 种超级神器超过数量限制的方案数
                  -...+...
    那么就下来就需要解决两个问题:
    1).如果随便选的话,如何求出方案数?
    假设需要从 N 种任意宝具里选出不超过 m 个,求法如下:
    先考虑必须选 m 个:
    这是一个典型的组合问题:
    即要把 m 个相同的小球放到 N 个盒子里,且盒子可以为空,求方案数。
    则方案数为 ${C}_{N+m-1}^{N-1}$。
    怎么理解呢? 可以叫做 "插隔板法" 吧。
    如果现在有 N+m-1 个位置,我们可以在 N-1 个位置放隔板,
    并且令相邻的两个隔板(把首尾也看作另外2个隔板)中间的空余位置放小球。
    (相邻的两个隔板之间共有 N 个间隙,所以可以把每个间隙依次看做一个盒子。)
    则任意一种插隔板的方法都对应一种把小球放入盒子的方法。
    所以,方案数为
    ${C}_{N+m-1}^{N-1}$

    但是这是必须选m个的方案数。
    所以需要把下面东西加起来才是选的物品不超过 m个 的方案数

    ${W=}{C}_{N-1}^{N-1}+{C}_{N}^{N-1}+{C}_{N+1}^{N-1}+cdots+{C}_{N+m-1}^{N-1}$
    然后需要化简这个式子:由一个小性质 : ${C}_{i-1}^{j}+{C}_{i-1}^{j-1}={C}_{i}^{j}$

    所以 ${W} = {W} + {C}_{N-1}^{N} – {C}_{N-1}^{N}$
    然后就可以从前面一直结合到末尾,得到
    ${W} = {C}_{N+m}^{N} – {C}_{N-1}^{N}$,但是 ${C}_{N-1}^{N}={0}$
    所以  ${W} = {C}_{N+m}^{N}$
    然后第一个问题就这么愉快地解决了。
    (哦,还有,这个组合数的 N,M都太大了但模数 P 很小,需要用到Lucas定理,不会的快百度百科一下!)
    2).如何求出那些用于容斥的方案数呢?
    考虑将一些超级神器强制超过使用其限制的个数(设超出的总个数为 k),
    那么在接下来,在 N 种宝具里任意选出不超过剩下的 m=M-k 个物品的方案都为非法方案,
    而这个方案数就可以用第一个问题的解决方法去求解。

    所以具体做法就是枚举一个集合 S表示该集合里的超级神器会被强制使用超过使用其限制的个数,
    然后求出该情况下的方案数后,对应着本文开篇的容斥式子去加加减减就好啦。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #define _ % P
    #define filein(x) freopen(#x".in","r",stdin);
    #define fileout(x) freopen(#x".out","w",stdout);
    using namespace std;
    int B[100500],h[100500],k[100500],fac[100500],inv[100500];
    int N,T,M,P,ANS;
    int pow(int a,int b){
    	int ret=1;
    	while(b){
    		if(b&1) ret=(1ll*ret*a)_;
    		a=(1ll*a*a)_; b>>=1;
    	}
    	return ret;
    }
    int C(int n,int m){
    	if(n<m) return 0;
    	return 1ll*fac[n]*inv[m]_*inv[n-m]_;
    }
    int Lucas(int n,int m){
    	int ret=1;
    	while(m){
    		ret=(1ll*ret*C(n%P,m%P))_;
    		n/=P; m/=P;
    	}
    	return ret;
    }
    int main()
    {
    	scanf("%d%d%d%d",&N,&T,&M,&P); fac[0]=inv[0]=1;
    	for(int i=1;i<P;i++) fac[i]=(1ll*fac[i-1]*i)_;
    	inv[P-1]=pow(fac[P-1],P-2);
    	for(int i=P-2;i;i--) inv[i]=(1ll*inv[i+1]*(i+1))_;
    	for(int i=1;i<=T;i++) scanf("%d",&B[1<<(i-1)]);
    	for(int s=1,q;q=(s&-s),s<(1<<T);s++) 
    		k[s]=1ll*k[s^q]+B[q]+1,
    		h[s]=h[s^q]+1;
    	for(int s=0,m,tmp;s<(1<<T);s++){
    		m=M-k[s]; if(m<0) continue;
    		tmp=Lucas(N+m,N);
    		if(h[s]&1) tmp=(-1ll*tmp+P)_;
    		ANS=((1ll*ANS+tmp)_+P)_;
    	}
    	printf("%d",ANS);
    	return 0;
    }
    

  • 相关阅读:
    python Database Poll for SQL SERVER
    SQLAlchemy表操作和增删改查
    flask动态url规则
    flask配置管理
    一个Flask运行分析
    Function Set in OPEN CASCADE
    Happy New Year 2016
    Apply Newton Method to Find Extrema in OPEN CASCADE
    OPEN CASCADE Multiple Variable Function
    OPEN CASCADE Gauss Least Square
  • 原文地址:https://www.cnblogs.com/zj75211/p/8040122.html
Copyright © 2020-2023  润新知