牛客國慶集訓派對Day4-E-乒乓球(NTT)
阿新 • • 發佈:2018-12-24
題目描述
小 Bo 是某省乒乓球名列前茅的選手,現在他有 n 顆乒乓球一字排開,第 i 顆乒乓球的權值為 wi
每次他會隨機從現有的乒乓球中等概率選一顆拿走,然後得到的收益是這顆球左邊第一個乒乓球和右邊第一個乒乓球的權值的乘積,如果左邊沒有乒乓球或者右邊沒有乒乓球,則收益為 0,這個過程會重複進行到所有球都被拿走為止
現在小 Bo 想知道他的期望總收益
為了方便,你只需要輸出答案對 998244353 取模的值
輸入描述:
第一行一個正整數 n 第二行 n 個正整數 w1…wn
輸出描述:
輸出答案對 998244353 取模的值
示例1
輸入
3 1 1 1
輸出
332748118
說明
答案是
備註:
1≤ n≤ 105 1≤ wi≤ 107
#include<stdio.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; #define ll long long #define mod 998244353 ll a[300005],b[300005],n,ans; ll wn[30]; ll q(ll x,ll y) { ll res=1;x%=mod; while(y) { if(y%2) res=res*x%mod; x=x*x%mod; y/=2; } return res; } void getwn() { for(int i=0;i<20;i++) { int tmp=1<<i; wn[i]=q(3ll,(mod-1)/tmp); } } void change(ll y[],int len) { int i,j,k; for(i=1,j=len/2;i<len-1;i++) { if(i<j) swap(y[i],y[j]); k=len/2; while(j>=k) j-=k,k/=2; if(j<k) j+=k; } } void ntt(ll y[], int len, int on) { change(y, len); int id=0; for(int h=2;h<=len;h<<=1) { id++; for(int j=0;j<len;j+=h) { ll w=1; for(int k=j;k<j+h/2;k++) { ll u=y[k]; ll t=w*y[k+h/2]%mod; y[k]=(u+t)%mod; y[k+h/2]=(u-t+mod)%mod; w=w*wn[id]%mod; } } } if(on==-1) { ll inv=q(len,mod-2); for(int i=1;i<len/2;i++) swap(y[i],y[len-i]); for(int i=0;i<len;i++) y[i]=y[i]*inv%mod; } } int main(void) { getwn(); scanf("%lld",&n); for(int i=0;i<n;i++) scanf("%lld",&a[i]); for(int i=0;i<n;i++) b[n-i-1]=a[i]; int len=1; while(len<=n*2) len*=2; ntt(a,len,1);ntt(b,len,1); for(int i=0;i<len;i++) a[i]=a[i]*b[i]%mod; ntt(a,len,-1); for(int i=2;i<n;i++) ans=(ans+2ll*a[n+i-1]*q((ll)i*(i+1),mod-2)%mod)%mod; printf("%lld\n",ans); return 0; }