一応分かった気がするのでメモ 議論間違ってたらすいません…
リンク
https://codeforces.com/contest/1349/problem/D
問題概要
N体のスライムがいてそれぞれ枚ずつビスケットを所持している。毎ターン毎に次の操作を繰り返す。
- 枚から一つ等確率でビスケットを選び、その現在の持ち主以外のN-1体から等確率で選んだ1体に渡す
操作の終了条件は初めてある1体が全てのビスケットを所持することである。操作の期待回数をmod998244353 で求めよ。
制約
考察
ある1体が全てのビスケットを所持するまでの期待回数
→位置iで操作が終了する確率を、その期待値をとすると求める期待値はである
以下とする、またが成立している
また操作の終了とは別に位置iにだけ注目した時に初めて全てのビスケットが揃うまでの期待回数をとすると、Cを定数として全てのj=1,2,…,nに対して が成立する
ここでCは位置iでビスケットを全て占めた状態から位置jでビスケットを全て占めた状態になるまでの期待回数を表していて、これはi,jのペアに依らない定数として扱うことができる
上式を変形して、
これをj=1,2,…,nについて和を取ることで、
(この式変形には を用いた)
両辺をnで割ると左辺が求めたい値になっていることから及び定数Cを求めることができれば良い
ここで次のような値を考える
この時、, である
このdpは次のように求めていくことができる
を求めて後ろから累積和を取る
この値はi番目とi-1番目の関係を漸化式で表すことで求めることができる
これを整理すると, が得られる
これを実装することで問題を解くことができます
実装
#include <iostream> #include <algorithm> #include <vector> using namespace std; typedef long long int ll; constexpr ll mod=998244353; ll dp[300300]; ll mod_pow(ll a,ll b){ a%=mod; if(b==0)return 1; if(b==1)return a; ll res=mod_pow(a,b/2)%mod; res*=res; res%=mod; if(b%2)res*=a; return res%mod; } int main(){ cin.tie(nullptr); ios::sync_with_stdio(false); int n; cin >> n; vector<int> a(n); int sum=0; for(int i=0;i<n;i++){ cin >> a[i]; sum+=a[i]; } dp[0]=n-1; // dp[i]=1+{(sum-i)/sum}*{1/(n-1)}+{(sum-i)/sum}*{(n-2)/(n-1)}*dp[i]+{i/sum}*(dp[i-1]+dp[i]) for(int i=1;i<sum;i++){ ll a=(sum-i)*mod_pow(sum,mod-2)%mod*mod_pow(n-1,mod-2)%mod; ll b=1+i*mod_pow(sum,mod-2)%mod*dp[i-1]%mod; dp[i]=b*mod_pow(a,mod-2)%mod; } for(int i=sum-1;i>=0;i--){ (dp[i]+=dp[i+1])%=mod; } ll res=0; for(int i=0;i<n;i++){ (res+=dp[a[i]])%=mod; } (res-=dp[0]*(n-1)%mod)%=mod; if(res<0)res+=mod; printf("%lld\n",res*mod_pow(n,mod-2)%mod); }