HDU20260820B 大户爱的硬币
第一道写出的计数题!!!!
题目描述:
一次抛硬币抛到正面的概率是 p 。
求 Var[Xk] ,其中 Var[X] 表示随机变量的方差(即 E[(X−E[X])2] ), X 表示第一次抛硬币抛到正面的次数。结果对 998244353 取模。
0<p<998244352,k≤2×105 。
看起来非常原题,且非常可以爆标。
首先, Var[X]=E[X2]−E[X]2 ,所以题目求的东西实际上是 E[X2k]−E[Xk]2 ,本质上是求 E[Xk] 。
考虑斯特林反演,则由期望的线性性得原式为 i=0∑ki!{ik}E[(iX)] 。
其中 {ik} 可以使用 FFT O(nlogn) 求出。所以问题变为求 E[(iX)] 。
考虑强行展开,得:
E[(iX)]=j=1∑∞p(1−p)j−1(ij)=pj=0∑∞(1−p)j(ij+1)
不妨设 Fi(x) 为 (ij+1) 的生成函数,那么就有 E[(iX)]=p×F(1−p) 。
设 Gi(x) 为 (ij) 的生成函数,那么就有 Fi(x)=xGi(x) 。
然后:
Gi(x)=j=0∑∞(ij)xj=j=0∑∞(ij−1)xj+j=0∑∞(i−1j−1)xj=x(Gi−1(x)+Gi(x))
解得 Gi(x)=1−xxGi−1(x) ,边界条件 G0(x)=1−x1 。
所以 Gi(x)=(1−x)i+1xi−1 。
然后代入计算即可。
复杂度 O(nlogn) 。(隔壁使用 O(nlog2n) 的分治 FFT T 废了)。
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
| #include <bits/stdc++.h> using namespace std; const int N=1300010,P=998244353; int R[N],fac[N],inv[N]; int kpow(int a,int b){ int t=1; while(b){ if(b&1)t=1ll*t*a%P; a=1ll*a*a%P; b>>=1; } return t; } void NTT(vector<int>&f,int t){ int len=f.size(); for(int i=0;i<len;i++)if(i<R[i])swap(f[i],f[R[i]]); for(int i=2;i<=len;i<<=1){ int G=kpow(t==1?3:kpow(3,P-2),(P-1)/i); for(int j=0;j<len;j+=i){ int g=1; for(int k=j;k<(j+(i>>1));k++){ int x=f[k],y=1ll*g*f[k+(i>>1)]%P; f[k]=(x+y)%P; f[k+(i>>1)]=(x-y+P)%P; g=1ll*G*g%P; } } } if(t==-1){ int in=kpow(len,P-2); for(int i=0;i<len;i++)f[i]=1ll*f[i]*in%P; } } void mul(vector<int>&x,vector<int>&y){ int len=1,l=0; while(len<=(x.size()+y.size()-2))len<<=1,l++; for(int i=0;i<len;i++)R[i]=(R[i>>1]>>1)|((i&1)<<(l-1)); x.resize(len);y.resize(len); NTT(x,1);NTT(y,1); for(int i=0;i<len;i++)x[i]=1ll*x[i]*y[i]%P; NTT(x,-1); } vector<int> stiring(int n){ vector<int>a(n+1),b(n+1); for(int i=0;i<=n;i++){ a[i]=1ll*kpow(i,n)*inv[i]%P; b[i]=1ll*kpow(P-1,i)*inv[i]%P; } mul(a,b); a.resize(n+1); return a; } void WZH(){ int k,p; scanf("%d%d",&k,&p); int q=(1-p+P)%P; vector<int>a=stiring(k); int ans=0,res=0; for(int i=0;i<=k;i++){ int t=1ll*fac[i]*a[i]%P; if(i)t=1ll*t*kpow(q,i-1)%P*kpow(kpow(p,i),P-2)%P; (res+=t)%=P; } ans=(P-1ll*res*res%P)%P; a=stiring(2*k); for(int i=0;i<=2*k;i++){ int t=1ll*fac[i]*a[i]%P; if(i)t=1ll*t*kpow(q,i-1)%P*kpow(kpow(p,i),P-2)%P; (ans+=t)%=P; } printf("%d\n",ans); return ; } int main(){ fac[0]=1; for(int i=1;i<=400000;i++)fac[i]=1ll*i*fac[i-1]%P; inv[400000]=kpow(fac[400000],P-2); for(int i=400000-1;i>=0;i--)inv[i]=1ll*inv[i+1]*(i+1)%P; int T; scanf("%d",&T); while(T--)WZH(); return 0; }
|