题意
链接:https://www.nowcoder.com/acm/contest/204/E
来源:牛客网
小 Bo 是某省乒乓球名列前茅的选手,现在他有 n 颗乒乓球一字排开,第 i 颗乒乓球的权值为 wi
每次他会随机从现有的乒乓球中等概率选一颗拿走,然后得到的收益是这颗球左边第一个乒乓球和右边第一个乒乓球的权值的乘积,如果左边没有乒乓球或者右边没有乒乓球,则收益为 0,这个过程会重复进行到所有球都被拿走为止
现在小 Bo 想知道他的期望总收益
为了方便,你只需要输出答案对 998244353 取模的值
分析
每确定一种排列方式,就能确定一种价值,每种排列出现是等概率的
考虑pair (x , y ) 能产生f(x)*f(y)价值的排列满足x+1、...、y-1都出现在x,y的前面,且y-x-1 > 0
通过计数原理推导:
x+1 ... y-1 共y-x-1个数字,共(y-x-1)!种排列方式
x y 共2个数字,共2!种排列方式
由乘法原理 x ... y共y-x+1个数字 排列方式 2*(y-x-1)!
将y-x+1个数字填入n个空中 共C(n,y-x+1)种方式
剩余n-y+x-1个数字共有(n-y+x-1)!排列方式
综上,pair(x,y)能产生价值的排列方案数为
2*(y-x-1)!*C(n,y-x+1)*(n-y+x-1)!
= 2* n!/ [(y-x+1)* (y-x)] 可以看出仅与y-x有关,由于要求期望,最后需要除以总方案数n!,所以pair(x,y)能产生价值的权值为 2/[(y-x+1)*(y-x)] y-x-1>0
所以按y-x分类,计算出∑a[y]*a[x]
构造数字a2[n-i-1] = a[i] 这样原式变成了∑a[y]*a2[n-x-1] = sum[n+y-x-1]
这里可以考虑用NTT
然后对于每个y-x乘上上述系数即可
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int g=3; 5 const int N=1e5; 6 const ll mod=998244353; 7 int n; 8 ll a[(N<<2)+5],a2[(N<<2)+5],inv[(N<<2)+5],sum[(N<<2)+5]; 9 ll quick_mod(ll a,ll b){ 10 ll res=1; 11 while(b){ 12 if(b&1)res=res*a%mod; 13 a=a*a%mod; 14 b>>=1; 15 } 16 return res; 17 } 18 int rev(int x,int r){ 19 int ans=0; 20 for(int i=0;i<r;i++){ 21 if(x&(1<<i)) ans+=1<<(r-i-1); 22 } 23 return ans; 24 } 25 void NTT(int n,ll A[],int on){ 26 int r=0; 27 for(;;r++) if((1<<r)==n)break; 28 for(int i=0;i<n;i++){ 29 int tmp=rev(i,r);; 30 if(i<tmp)swap(A[i],A[tmp]); 31 } 32 for(int s=1;s<=r;s++){ 33 int m=1<<s; 34 ll wn=quick_mod(g,(mod-1)/m); 35 for(int k=0;k<n;k+=m){ 36 ll w=1; 37 for(int j=0;j<(m>>1);j++){ 38 ll t,u; 39 t=w*(A[k+j+(m>>1)]%mod)%mod; 40 u=A[k+j]%mod; 41 A[k+j]=(u+t)%mod; 42 A[k+j+(m>>1)]=((u-t)%mod+mod)%mod; 43 w=w*wn%mod; 44 } 45 } 46 } 47 if(on==-1){ 48 for(int i=1;i<(n>>1);i++)swap(A[i],A[n-i]); 49 ll inv = quick_mod(n,mod-2); 50 for(int i=0;i<n;i++) A[i]=A[i]%mod*inv%mod; 51 } 52 } 53 54 int main(){ 55 scanf("%d",&n); 56 for(int i=1;i<=n;i++)scanf("%lld",&a[i]); 57 if(n<=2){ 58 cout<<"0"<<endl; 59 return 0; 60 } 61 for(int i=1;i<n;i++) a2[n-i-1]=a[i]; 62 inv[1]=1; 63 for(int i=2;i<=n;i++)inv[i]=inv[mod%i]*(mod-mod/i)%mod; 64 ll len=1; 65 while(len<(n<<1))len<<=1; 66 NTT(len,a,1); 67 NTT(len,a2,1); 68 for(int i=0;i<len;i++)sum[i] = a[i]*a2[i]%mod; 69 NTT(len,sum,-1); 70 ll ans=0; 71 for(int k=3;k<=n;k++){ 72 int i=n+k-2; 73 ans= (ans+sum[i]*inv[k]%mod*inv[k-1]%mod)%mod; 74 } 75 ans = ans * 2 % mod; 76 printf("%lld\n",ans); 77 }