【2019北京集训测试赛(七)】 操作 分治+FFT+生成函数
题目大意:你有n个操作和一个初始为0的变量x。
第i个操作为:以Pi的概率给x加上Ai,剩下1−Pi的概率给x乘上Bi。
你袭击生成了一个长度为n的排列C,并以此执行了第C1,C2....Cn个操作。
求执行完所有操作后,变量x的期望膜998244353的值。
数据范围:n≤105,0≤P,A,B<998244353
我太菜了。
考虑如果并没有排列的要求,而是强行依次执行,会发生什么事情:
令Xi表示执行完前i个操作后x的期望。
则有:
Xi=Pi×(Xi−1+Ai)+(1−Pi)×Xi−1×Bi
我们经过化简,得到:
Xi=(Pi+Bi−Pi×Bi)Xi−1+Ai×Bi
这个不就是一个一次函数吗?我们姑且将这个称为Fi(x),我们将它表示为Fi(x)=Dix+Ei
那么在不考虑顺序的情况下,则有:
Xn=F1(F2(...Fn(0)...))
然而求答案的时候,函数排列的顺序是随机的,对于任意的i≠j,函数i排在函数j前面的概率都是12。
我们只需要求出,对于每个Ei,套在Fi(x)外面的函数的积的期望。
基于这些,则有:
Xn=1n!n∑i=1Ein∑j=1[xj]n∏k=1,k≢i(1+Dk)
然后,我们通过分治FFT求解这个式子即可。
1 #include<bits/stdc++.h> 2 #define MOD 998244353 3 #define G 3 4 #define L long long 5 #define M 262144 6 using namespace std; 7 8 L pow_mod(L x,L k){L ans=1; for(;k;k>>=1,x=x*x%MOD) if(k&1) ans=ans*x%MOD; return ans;} 9 void chage(int a[],int n){ 10 for(int i=0,j=0;i<n-1;i++){ 11 if(i<j) swap(a[i],a[j]); 12 int k=n>>1; 13 while(j>=k) j-=k,k>>=1; 14 j+=k; 15 } 16 } 17 inline int pls(int a,int b){return a+b>=MOD?a+b-MOD:a+b;} 18 inline int mns(int a,int b){return a<b?a-b+MOD:a-b;} 19 void NTT(int a[],int n,int on){ 20 chage(a,n); 21 for(int h=2;h<=n;h<<=1){ 22 int wn=pow_mod(G,(MOD-1)/h); 23 for(int j=0;j<n;j+=h){ 24 int w=1; 25 for(int k=j;k<j+(h>>1);k++){ 26 int u=a[k],t=1LL*a[k+(h>>1)]*w%MOD; 27 //a[k]=(u+t)%MOD; a[k+(h>>1)]=(u-t+MOD)%MOD; 28 a[k]=pls(u,t); a[k+(h>>1)]=mns(u,t); 29 w=1LL*w*wn%MOD; 30 } 31 } 32 } 33 if(on==-1){ 34 L inv=pow_mod(n,MOD-2); 35 reverse(a+1,a+n); 36 for(int i=0;i<n;i++) a[i]=1LL*a[i]*inv%MOD; 37 } 38 } 39 void MUL(int ans[],int a[],int lena,int b[],int lenb){ 40 static int t1[M],t2[M]; 41 int len=1; while(len<=lena+lenb) len<<=1; 42 memset(t1,0,len<<2); memcpy(t1,a,(lena+1)<<2); 43 memset(t2,0,len<<2); memcpy(t2,b,(lenb+1)<<2); 44 NTT(t1,len,1); NTT(t2,len,1); 45 for(int i=0;i<len;i++) t1[i]=1LL*t1[i]*t2[i]%MOD; 46 NTT(t1,len,-1); 47 memcpy(ans,t1,(lena+lenb+1)<<2); 48 } 49 50 L D[M]={0},E[M]={0},fac[M]={0}; 51 void solve(int f[],int g[],int l,int r){ 52 static int h[M]; 53 if(l==r) return f[0]=E[l],g[1]=D[l],g[0]=1,void(); 54 int mid=(l+r)>>1,lenl=mid-l+1,lenr=r-mid; 55 solve(f,g,l,mid); solve(f+lenl+2,g+lenl+2,mid+1,r); 56 MUL(h,f,lenl-1,g+lenl+2,lenr); 57 MUL(f,f+lenl+2,lenr-1,g,lenl); 58 for(int i=0;i<=r-l+1;i++) f[i]=(f[i]+h[i])%MOD; 59 MUL(g,g,lenl,g+lenl+2,lenr); 60 } 61 62 int ff[M]={0},gg[M]={0}; 63 int main(){ 64 fac[0]=1; for(int i=1;i<M;i++) fac[i]=fac[i-1]*i%MOD; 65 int n; scanf("%d",&n); 66 for(int i=1;i<=n;i++){ 67 L P,B,A; scanf("%lld%lld%lld",&P,&A,&B); 68 D[i]=(P+B-P*B%MOD+MOD)%MOD; 69 E[i]=A*P%MOD; 70 } 71 solve(ff,gg,1,n); 72 L ans=0; 73 for(int i=0;i<n;i++) (ans+=1LL*ff[i]*fac[i]%MOD*fac[n-i-1])%=MOD; 74 ans=ans*pow_mod(fac[n],MOD-2)%MOD; 75 cout<<ans<<endl; 76 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!