zoukankan      html  css  js  c++  java
  • Atcoder Regular Contest 061 D Card Game for Three(组合数学)

    洛谷题面传送门 & Atcoder 题面传送门

    首先考虑合法的排列长什么样,我们考虑将每次操作者的编号记录下来形成一个序列(第一次 A 操作不计入序列),那么显然这个序列中必须恰好含有 \(n\) 个 A,且最后一个必须是 A。那么显然一个合法的取卡片方案唯一对应一个操作序列,而一个长度为 \(l\) 的操作序列恰好对应 \(3^{n+m+k-l}\) 个合法的取卡片方案(证明?就每次下一轮执行操作的人是谁就在对应的操作者所取的卡片上写啥,那么显然对于长度为 \(l\) 的操作序列而言,在原卡片堆中恰好有 \(l\) 张卡片上的数是确定下来的,另外 \(n+m+k-l\) 张可以 randomly 乱填,方案数就是 \(3^{n+m+k-l}\)

    然后考虑怎样统计方案,我们枚举操作序列中 BC 出现次数 \(c\),那么操作序列长度即为 \(c+n\),其中有一个 A 的位置已经确定了,那么填好另外 \(n-1\) 个 A 的方案数即是 \(\dbinom{n+c-1}{n-1}\),如果我们能求出填好 B、C 的方案数 \(f_k\),就有 \(ans=\sum\limits_{c=0}^{m+k}\dbinom{n+c-1}{n-1}f_c·3^{m+k-c}\)

    接下来考虑怎样求 \(f_c\),首先列出柿子,枚举 B 的个数然后组合数统计答案,即

    \[f_c=\sum\limits_{i}\dbinom{c}{i}[i\le m][c-i\le k] \]

    上式也可以写作

    \[f_c=\sum\limits_{c-k\le i\le m}\dbinom{c}{i} \]

    我们知道组合数下底数求和是无法直接求的,不过注意到组合数有个递推公式 \(\dbinom{n}{k}=\dbinom{n-1}{k}+\dbinom{n-1}{k-1}\),因此考虑从数列递推的角度理解这道题,即:

    \[\begin{aligned} f_c&=\sum\limits_{c-k\le i\le m}\dbinom{c}{i}\\ &=\sum\limits_{c-k\le i\le m}\dbinom{c-1}{i}+\dbinom{c-1}{i-1}\\ &=\sum\limits_{c-k\le i\le m}\dbinom{c-1}{i}+\sum\limits_{c-k\le i\le m}\dbinom{c-1}{i-1}\\ &=\sum\limits_{c-k\le i\le m}\dbinom{c-1}{i}+\sum\limits_{c-k-1\le i\le m-1}\dbinom{c-1}{i}\\ &=2\sum\limits_{c-1-k\le i\le m}\dbinom{c-1}{i}-\dbinom{c-1}{m}-\dbinom{c-1}{c-k-1}\\ &=2f_{c-1}-\dbinom{c-1}{m}-\dbinom{c-1}{c-k-1} \end{aligned} \]

    递推求一下即可,时间复杂度线性。

    const int MAXN=9e5; 
    const int MOD=1e9+7;
    int n,m,k,fac[MAXN+5],ifac[MAXN+5],f[MAXN+5],pw3[MAXN+5];
    void init_fac(int n){
    	for(int i=(fac[0]=ifac[0]=ifac[1]=pw3[0]=1)+1;i<=n;i++) ifac[i]=1ll*ifac[MOD%i]*(MOD-MOD/i)%MOD;
    	for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%MOD,ifac[i]=1ll*ifac[i-1]*ifac[i]%MOD;
    	for(int i=1;i<=n;i++) pw3[i]=3ll*pw3[i-1]%MOD;
    }
    int binom(int x,int y){
    	if(x<0||y<0||x<y) return 0;
    	return 1ll*fac[x]*ifac[y]%MOD*ifac[x-y]%MOD;
    }
    int main(){
    	scanf("%d%d%d",&n,&m,&k);init_fac(n+m+k);
    	f[0]=1;for(int i=1;i<=m+k;i++)
    		f[i]=(2ll*f[i-1]-binom(i-1,m)-binom(i-1,i-k-1)+MOD*2ll)%MOD;
    	int ans=0;for(int i=0;i<=m+k;i++) ans=(ans+1ll*pw3[m+k-i]*binom(n-1+i,i)%MOD*f[i])%MOD;
    	printf("%d\n",ans);
    	return 0;
    }
    
  • 相关阅读:
    如何自定义长连接策略
    知物由学 | 这些企业大佬如何看待2018年的安全形势?
    网易云易盾朱星星:最容易被驳回的10大APP过检项
    网易云易盾朱浩齐:视听行业步入强监管和智能时代
    知物由学 | 人工智能、机器学习和深度学习如何在网络安全领域中应用?
    知物由学 | 广告欺诈:如何应对数字广告里分羹者?
    知物由学 | 如何应对日益强大的零日攻击
    不再任人欺负!手游安全的进阶之路
    邪恶的三位一体:机器学习、黑暗网络和网络犯罪
    PAT 1053. Path of Equal Weight
  • 原文地址:https://www.cnblogs.com/ET2006/p/arc061D.html
Copyright © 2011-2022 走看看