zoukankan      html  css  js  c++  java
  • Crash的游戏 [组合+递推]

    题面

    思路

    问题转化

    这个问题的核心在于,我们需要把“加入一个球、拿出一个球”这两个操作转化一下

    因为显然两个操作同时进行的话,我们没有办法从单纯的组合意义去分析

    我们首先把$m$个球拿出来,表示全部都选拿走球

    然后对于我们选定的加入球的操作,我们一次性加入两个球

    这样问题就变成了一个单纯加入球的问题了

    左右分开

    现在的问题是这样的:

    给定$n-m$个球,你有$m$次机会,每次可以加入两个球,最后你会拿出$k$个球,问总方案数

    我们把$k$个球的来源分开考虑

    假设$k$个里面有$i$个来自于原来的$n-m$个球,$k-i$个来自于新加入的球

    那么选出$i$个的方案数应该为$C^i_{n-m}$

    后面新加入的球,我们考虑一个递推:$f[i][j]$表示从$i$对球中拿了东西,一共取出来了$j$个

    那么新加入一对球,可以选择拿一个或者拿两个,因此可以写出方程

    $g[i][j]=f[i-1][j-2]+f[i-1][j-1]*2$

    计算答案

    这个方程得到之后就好办了

    我们先枚举$k$个里面从原来球中选出的个数,再枚举剩下的$k-i$用了多少对球($j$)

    然后除了上面的两个东西要乘起来之外,还要再乘以$C{m}_j$和$2{m-j}$,分别表示选出$j$对的方案,以及剩下的没有取出的东西做出的贡献

    式子如下:

    $Ans = sum_{i=0}^k sum_{j= frac{k-i}{2} }^{k-i } C(n-m,i) ast C(m,j) ast 2^{m-j} ast f[k-i][j]$

    这里面的组合数每次询问单独处理,$f$数组可以预处理好,总复杂度$O(Tk^2)$

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define ll long long
    #define MOD 1000000007
    using namespace std;
    ll n,m,k,f[1010][1010],suf[510],suff[510],pre[510],C[510],CC[510],pw[510];
    ll qpow(ll a,ll b){
    	ll re=1;
    	if(b<0) return 0;
    	while(b){
    		if(b&1) re=re*a%MOD;
    		a=a*a%MOD;b>>=1;
    	}
    	return re;
    }
    void init(ll p,ll q){
    	memset(C,0,sizeof(C));memset(CC,0,sizeof(CC));
    	int i;C[0]=1;CC[0]=1;
    	suf[1]=p;suff[1]=q;
    
    	for(i=2;i<=min(p,k);i++) suf[i]=suf[i-1]*(p-i+1ll)%MOD;
    	for(i=2;i<=min(q,k);i++) suff[i]=suff[i-1]*(q-i+1ll)%MOD;
    
    	for(i=1;i<=min(p,k);i++) C[i]=suf[i]*pre[i]%MOD;
    	for(i=1;i<=min(q,k);i++) CC[i]=suff[i]*pre[i]%MOD;
    }
    void getf(){
    	int i,j,len=310;
    	f[0][0]=1;
    	for(i=1;i<=len;i++){
    		for(j=1;j<=i*2;j++){
    			f[i][j]=(f[i-1][j-1]*2+f[i-1][j-2])%MOD;
    		}
    	}
    }
    int main(){
    	getf();int T;scanf("%d",&T);
    	pre[1]=1;
    	for(int i=2;i<=500;i++) pre[i]=(pre[i-1]*qpow(i,MOD-2))%MOD;
    	while(T--){
    		scanf("%lld%lld%lld",&n,&m,&k);
    		init(n-m,m);
    		ll ans=0,tmp;int i,j;
    		for(i=0;i<=k;i++) pw[i]=qpow(2,m-i);
    		for(i=0;i<=k;i++){
    			tmp=0;
    			for(j=(k-i+1)/2;j<=k-i;j++){
    				(tmp+=CC[j]*pw[j]%MOD*f[j][k-i]%MOD)%=MOD;
    			}
    			(ans+=tmp*C[i]%MOD)%=MOD;
    		}
    		printf("%lld
    ",ans);
    	}
    }
    
  • 相关阅读:
    importToMbtiles
    http-server服务跨域设置
    Leaflet 测试加载高德地图
    矢量切片
    zigzag方式编码
    CentOS7安装docker
    CentOS7安装NodeJS
    CentOS7上Python3.5安装
    JDK8下maven使用maven-javadoc-plugin插件报错
    Ubuntu16.10上安装NodeJS6.9.2
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/9724121.html
Copyright © 2011-2022 走看看