C - Catastrophic Roulette 解説 by evima
Let \(q\) be the number of distinct integers that have appeared, and consider managing the following quantities for each value of \(q\):
- The probability that it is the first/second player’s turn right after the number of distinct integers has become \(q\), denoted as \(h_1, h_2\)
- The expected amount of the fine paid by the first/second player at the moment right after the number of distinct integers has become \(q\), denoted as \(f_1, f_2\)
The problem can be solved by updating these quantities for \(q=1,2,\dots,N\) in order.
Let’s formulate this carefully.
For \(q=1\), we have \(h_1=0, h_2=1, f_1=0, f_2=0\).
Hereafter, let \(\displaystyle p=\frac{q}{N}\).
First, focus on updating \(h\).
The probability that the player who plays right after the number of distinct integers has become \(q+1\) is different from the player who plays right after it has become \(q\) is expressed as \(\displaystyle (1-p) + (1-p)p^2 + (1-p)p^4 + \dots\).
Next, focus on updating \(f\).
The expected value of the fine increase for the player who is playing is expressed as \(p + p^3 + p^5 + \dots\), and for the player who is not playing, it is \(p^2 + p^4 + p^6 + \dots\).
Although it seems difficult to handle these infinite sums, by utilizing that \(\displaystyle 1 + p^2 + p^4 + p^6 + \dots = \sum_{i=0}^{\infty} p^{2i} = \frac{1}{1-p^2}\) holds for \(0 < p < 1\), all of them can be processed.
Implementing this calculation allows you to solve this problem in time complexity \(O(N)\).
Bonus!
Let's consider why the "rational number judge" can be used for this problem (all calculations can be concluded with rational numbers whose denominators are not multiples of $998244353$).Sample implementation (C++):
#include<bits/stdc++.h>
#define mod 998244353
long long power(long long a,long long b){
long long x=1,y=a;
while(b>0){
if(b&1ll){
x=(x*y)%mod;
}
y=(y*y)%mod;
b>>=1;
}
return x%mod;
}
long long modular_inverse(long long n){
return power(n,mod-2);
}
using namespace std;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
long long n;
cin >> n;
long long invn=modular_inverse(n);
vector<long long> hand={0,1};
vector<long long> fee={0,0};
for(long long q=1;q<n;q++){
long long prob=(q*invn)%mod;
long long fce=modular_inverse(mod+1-((prob*prob)%mod));
long long hce=((mod+1-prob)*fce)%mod;
vector<long long> chand={
(prob*hce)%mod,
hce
};
vector<long long> cfee={
(prob*fce)%mod,
(((prob*prob)%mod)*fce)%mod,
};
vector<long long> nhand={0,0};
for(long long i=0;i<2;i++){
for(long long j=0;j<2;j++){
nhand[(i+j)%2]+=hand[i]*chand[j];
nhand[(i+j)%2]%=mod;
fee[(i+j)%2]+=hand[i]*cfee[j];
fee[(i+j)%2]%=mod;
}
}
hand=nhand;
}
cout << fee[0]%mod << " " << fee[1]%mod << "\n";
return 0;
}
投稿日時:
最終更新: