zoukankan      html  css  js  c++  java
  • CF1392H. ZS Shuffles Cards

    (n+m)个球,(n)个球上写着互不相同的数字,(m)个球为空白。有个初始为空的集合(S)。将(n+m)个球随机排列。
    从前往后操作,求期望操作多少次:

    1. 如果遇到一个数字(x),在(S)中丢入(x);在排列中删去(x)
    2. 如果遇到空白:如果(|S|=n),则退出;否则重新生成(n+m)个球的随机排列。

    (n,mle 2*10^6)


    好久没有在CF看见推式子题了啊。

    一开始看错题意直到发现

    原题求最后一个数出现的期望,首先很容易想到minmax容斥,枚举(T)算出(T)中的某个数第一次出现的期望。设(k=|T|)

    设生成函数(G(x))表示在做一轮(定义两次重排之间为一轮)的时候,操作(i)次退出的概率记在(x^i)上。

    显然有:

    [G_k(x)=sum_ifrac{inom{n-k}{i}i!(n+m-i-1)!m}{(n+m)!}x^{i+1} ]

    (F(x))表示这道题的概率生成函数,有:

    (F(x)=sum_{k=1}^ninom{n}{k}(-1)^{k-1}frac{G_0(x)-G_k(x)}{1-G_k(x)}\=sum_{k=1}^ninom{n}{k}(-1)^{k}(frac{1-G_0(x)}{1-G_k(x)}-1)\=(sum_{k=1}^ninom{n}{k}(-1)^{k}frac{1}{1-G_k(x)})(1-G_0(x))+1)

    根据概率生成函数的基本性质,有(E(x)=F'(1))。推一波式子之后得到:(注意推导过程中有用到(G_0(1)=1)

    [F'(1)=-sum_{k=1}^{n}inom{n}{k}(-1)^kfrac{1}{1-G_k(1)}G_0'(1) ]

    (G_0'(1))可以线性求。

    (G_k(1))考虑组合意义:原来是随机排列满足第一个空白之前,都是在(T)之外(n-k)个数字的概率。不妨转化成:(n-k)个不同球和(m+k)个不同标号的球插在一起,(n-k)个球内部顺序任意排列,(m+k)个球除第一个必须是空白的之外其它任意排列。于是有(G_k(1)=frac{inom{n-k}{n+m}(n-k)!(m+k-1)!m}{(n+m)!})。可以(O(1))求。

    于是时间复杂度是线性的。


    using namespace std;
    #include <bits/stdc++.h>
    #define N 2000005
    #define ll long long
    #define mo 998244353
    ll qpow(ll x,ll y=mo-2){
    	ll r=1;
    	for (;y;y>>=1,x=x*x%mo)
    		if (y&1)
    			r=r*x%mo;
    	return r;
    }
    int n,m;
    ll fac[N*2],ifac[N*2];
    void initC(int n){
    	fac[0]=1;
    	for (int i=1;i<=n;++i)
    		fac[i]=fac[i-1]*i%mo;
    	ifac[n]=qpow(fac[n]);
    	for (int i=n-1;i>=0;--i)
    		ifac[i]=ifac[i+1]*(i+1)%mo;
    }
    ll C(int m,int n){return fac[m]*ifac[n]%mo*ifac[m-n]%mo;}
    ll iC(int m,int n){return ifac[m]*fac[n]%mo*fac[m-n]%mo;}
    ll ans;
    int main(){
    //	freopen("in.txt","r",stdin);
    	scanf("%d%d",&n,&m);
    	initC(n+m);
    	ll p=0;
    	for (int i=0;i<=n;++i)
    		(p+=C(n,i)*fac[i]%mo*fac[n+m-i-1]%mo*ifac[n+m]%mo*(i+1))%=mo;
    	p=p*m%mo;
    	ll s=0;
    	for (int k=1;k<=n;++k){
    		ll t=0;
    //		for (int i=0;i<=n-k;++i)
    //			(t+=C(n-k,i)*fac[i]%mo*fac[n+m-i-1]%mo*ifac[n+m])%=mo;
    //		t=t*m%mo;
    		t=C(n+m,n-k)*fac[n-k]%mo*fac[m+k-1]%mo*m%mo*ifac[n+m]%mo;
    		(s+=(k&1?-1:1)*C(n,k)*qpow(1-t))%=mo;
    	}
    	ll ans=(-s*p%mo+mo)%mo;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    emacs 配置
    .Net微服务实践(五)[服务发现]:Consul介绍和环境搭建
    .Net微服务实践(四)[网关]:Ocelot限流熔断、缓存以及负载均衡
    .Net微服务实践(三)[网关]:Ocelot配置路由和请求聚合
    .Net微服务实践(二)[网关]:Ocelot介绍和快速开始
    .Net微服务实践(一)[框架]:微服务框架选型
    研发协同平台持续集成之Jenkins实践
    统一身份认证服务IdentityServer4实践
    DevOps平台架构演进
    ABP框架
  • 原文地址:https://www.cnblogs.com/jz-597/p/14345718.html
Copyright © 2011-2022 走看看