zoukankan      html  css  js  c++  java
  • CF1349D Slime and Biscuits 解题报告

    (n) 个人,第 (i) 个人有 (a_i)​ 个饼干,每次随机选择一个饼干,将其随机分配给除了它现在所有者的其他 (n-1) 个人,求使得一个人拥有所有饼干的期望步数,对 (998244353) 取模。

    (nle 10^5 , sum a_ile 3 imes 10^5)

    (E_i) 为所有饼干在第 (i) 个人手中的情况的期望时间那么总答案就是 (sumlimits_{i=1}^n E_i)

    显然这个东西并不好求,考虑加点东西转化一下,设 (D_i) 为所有饼干都在第 (i) 个人手中时才结束的期望时间, (P_i) 为所有饼干在第 (i) 个人手中的情况的概率,此时有 (sum P_i=1)

    设所有饼干从一个人全转移到另外一个人的期望时间是 (C) ,对于任意两人,这个 (C) 是一样的。

    那么可以列出关系式:

    [D_x=E_x+sumlimits_{i=1&i ot=x}^{n} (E_i+P_i imes C) ]

    也就是枚举第一次拿到所有饼干的人,再进行转移。

    考虑将 (i ot=x) 给消掉,将 (x=1,2,...,n) 的式子都加起来,可以得到:

    [sumlimits_{i=1}^n D_i=nsumlimits_{i=1}^n E_i + C imes (n-1)sumlimits_{i=1}^n P_i ]

    由于答案是 (sumlimits_{i=1}^n E_i) ,所以有 (Ans=sumlimits_{i=1}^n D_i - C(n-1))

    考虑如何求出 (D_x)(C) ,可以设一个 (f_x) 为目前有了 (x) 块饼干,收集到所有饼干的期望时间,显然有 (D_x=f_{a_x} , C=f_0)

    (0le x<sum) 时,有 (f_x=1+frac{sum-x}{sum}(frac{f_{x+1}}{n-1}+frac{(n-2)f_x}{n-1})+frac{xf_{x-1}}{sum}) , 显然有 (f_{sum}=0)

    上面的式子是判断选择的饼干,如果是他人的饼干,就有 (frac{1}{n-1}) 的概率给到自己, (frac{n-2}{n-1}) 的概率给别人,如果是自己的饼干,就一定会少掉一个。

    这个消元我不太懂,但是有一个神奇的思路,就是搞一个 (f_x) 的差分数组 (g_x=f_{x}-f_{x+1}) ,那么有 (f_x=sumlimits_{i=x}^{sum} g_i) ,其中 (g_{sum}=0)

    那原式可以写成 (f_{x+1} +g_x=1+frac{sum-x}{sum}(frac{f_{x+1}}{n-1}+frac{(n-2)(f_{x+1} +g_x)}{n-1})+frac{x(f_{x+1} +g_{x}+g_{x-1} )}{sum}) ,化简可得 (g_x=frac{sum(n-1)+x(n-1)g_{x-1}}{sum-x})

    那就可以 (mathcal{O(sum)}) 来递推出 (g_x)(f_x) 了。

    #include<bits/stdc++.h>
    using namespace std;
    
    #define int long long
    const int M=1e6+5,JYY=998244353;
    
    int read(){
    	int x=0,y=1;char ch=getchar();
    	while(ch<'0'||ch>'9') y=(ch=='-')?-1:1,ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return x*y;
    }
    
    int n,sum=0,Ans=0,a[M],inv[M],F[M];
    void solve(){
    	n=read();
    	for(int i=1;i<=n;i++) sum+=a[i]=read();
    	inv[0]=inv[1]=1;
    	for(int i=2;i<=max(sum,n);i++) inv[i]=(JYY-JYY/i)*inv[JYY%i]%JYY;
    	F[0]=n-1;
    	for(int i=1;i<sum;i++) F[i]=(sum*(n-1)%JYY+i*(n-1)%JYY*F[i-1]%JYY)*inv[sum-i]%JYY;
    	for(int i=sum-1;i>=0;i--) F[i]=(F[i+1]+F[i])%JYY;
    	for(int i=1;i<=n;i++) Ans=(Ans+F[a[i]])%JYY;
    	Ans=(Ans-F[0]*(n-1)%JYY+JYY)%JYY;
    	printf("%lld
    ",Ans*inv[n]%JYY);
    }
    
    signed main(){
    	solve();
    }
    
  • 相关阅读:
    BNU 51002 BQG's Complexity Analysis
    BNU OJ 51003 BQG's Confusing Sequence
    BNU OJ 51000 BQG's Random String
    BNU OJ 50999 BQG's Approaching Deadline
    BNU OJ 50998 BQG's Messy Code
    BNU OJ 50997 BQG's Programming Contest
    CodeForces 609D Gadgets for dollars and pounds
    CodeForces 609C Load Balancing
    CodeForces 609B The Best Gift
    CodeForces 609A USB Flash Drives
  • 原文地址:https://www.cnblogs.com/wzp-blog/p/14269297.html
Copyright © 2011-2022 走看看