T1 luogu 5249
题目大意:
有$n$个人按顺序坐成一圈玩游戏,从$1$号开始每次抛硬币,如果是正面就出局,无论结果如何都把硬币给下一个没出局的人
这个硬币概率是正面的概率为$p$由一个分数$\frac{a}{b}$的形式给出$a,b$,问$1-n$号人留到最后的概率在$\mod 998244353$下的数
思路:
设$f_{i,j}$表示总共还剩$i$个人的时候,若当前抛硬币的人编号为$1$,编号为$j$的人作为最后一个人的概率
则容易推出方程$f_{i,j}=p*f_{i-1,j-1}+q*f_{i,j-1}$,由于是环形所以需要消元
因为对每个$i$,需要所有$i-1$都已知才可以,这样我们一行一行使用高斯消元复杂度为$n^4$
考虑手动推系数,把一行内所有的$f_{i,j}$全部用$f_{i,1}$代替
推出$f_{i,1}$的系数和其余常数项,因为每一行的和都是$1$,算出$f_{i,1}$之后再带回去即可,复杂度$n^2$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MOD 998244353 15 #define MAXN 5010 16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 18 #define ren for(register int i=fst[x];i;i=nxt[i]) 19 #define mem(x,i) memset(x,i,sizeof(x)) 20 #define pb(i,x) vec[i].push_back(x) 21 #define pls(a,b) (a+b)%MOD 22 #define mns(a,b) (a-b+MOD)%MOD 23 #define mul(a,b) (1LL*(a)*(b))%MOD 24 using namespace std; 25 inline int read() 26 { 27 int x=0,f=1;char ch=getchar(); 28 while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} 29 while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} 30 return x*f; 31 } 32 int n,f[MAXN][MAXN],p,q,sum,k,tmp,s; 33 int q_pow(int bas,int t,int res=1) 34 { 35 for(;t;t>>=1,bas=mul(bas,bas)) 36 if(t&1) res=mul(res,bas);return res; 37 } 38 #define inv(x) q_pow(x,MOD-2) 39 int main() 40 { 41 freopen("A.in","r",stdin);freopen("A.out","w",stdout); 42 int a=read(),b=read();n=read();p=mul(inv(b),a),q=mns(1,p); 43 f[1][1]=1;rep(i,2,n) 44 { 45 s=sum=0,k=tmp=1;rep(j,2,i) tmp=mul(tmp,q),k=pls(k,tmp), 46 s=pls(mul(s,q),mul(p,f[i-1][j-1])),sum=pls(sum,s); 47 f[i][1]=mul(mns(1,sum),inv(k));rep(j,2,i) 48 f[i][j]=pls(mul(p,f[i-1][j-1]),mul(q,f[i][j-1])); 49 } 50 rep(i,1,n) printf("%d ",f[n][i]); 51 }