【題解】2020ICPC澳門 A.Accelerator
阿新 • • 發佈:2021-10-07
題意
給定一個長為\(n\)的序列\(\{a_i\}\),等概率隨機一個長為\(n\)的排列\(\{p_i\}\),求\(\{a_{p_i}\}\)的字尾積的和的期望。
\(1\le n\le 10^5,1\le a_i\le 10^9\)
題解
答案即為
\[\frac{1}{n!}\sum_{p}\sum_{i=1}^{n}\prod_{j\ge i}a_{p_{j}}. \]我們考慮一個長為\(k\)的項\(\prod_{j=1}^{k}a_{q_{j}}\)會在分子中出現多少次,相當於序列的後\(k\)個數隨機排列,前\(n-k\)個數隨機排列的方案數,故出現次數為\(k!(n-k)!\)
而
於是分治計算\(\prod_{i=1}^n(1+a_i x)\)即可。複雜度\(O(n\log^2n )\)
#include <bits/stdc++.h> using namespace std; using ll=long long; const int mod=998244353; const int N=100005; const double pi=acos(-1.0); inline int add(int x,int y){x+=y;return x>=mod?x-mod:x;} inline int mul(int x,int y){return 1ll*x*y%mod;} int pm(int x,int y){ int res=1; while(y){ if(y&1) res=mul(res,x); x=mul(x,x),y>>=1; } return res; } inline int getinv(int x){return pm(x,mod-2);} inline int getN(int x){ int N=1; while(N<=x) N<<=1; return N; } const int maxn=1<<18; namespace Poly{ int inv[maxn]; void init(int N){ inv[0]=inv[1]=1; for(int i=2;i<N;i++) inv[i]=mul(inv[mod%i],mod-mod/i); } void ntt(int *A,int N,int opt){ for(int i=0,j=0;i<N;i++){ if(i<j) swap(A[i],A[j]); for(int l=(N>>1);(j^=l)<l;l>>=1); } for(int l=2;l<=N;l<<=1){ int m=(l>>1),w0=pm(3,(mod-1)/l); if(opt==-1) w0=getinv(w0); for(int j=0;j<N;j+=l) for(int i=j,w=1;i<j+m;i++,w=mul(w,w0)){ int v=mul(A[i+m],w); A[i+m]=add(A[i],mod-v); A[i]=add(A[i],v); } } if(opt==-1){ int tmp=getinv(N); for(int i=0;i<N;i++) A[i]=mul(A[i],tmp); } } } using Poly::ntt; using poly=vector<int>; int A[maxn],B[maxn],C[maxn]; poly polymul(poly a,poly b){ poly c; int n=a.size()-1,m=b.size()-1; c.resize(n+m+1); int N=getN(n+m); for(int i=0;i<=n;i++) A[i]=a[i]; for(int i=n+1;i<N;i++) A[i]=0; for(int i=0;i<=m;i++) B[i]=b[i]; for(int i=m+1;i<N;i++) B[i]=0; ntt(A,N,1),ntt(B,N,1); for(int i=0;i<N;i++) A[i]=mul(A[i],B[i]); ntt(A,N,-1); for(int i=0;i<=n+m;i++) c[i]=A[i]; return c; } int n,b[N]; poly sol(int l,int r){ if(l==r){return poly{1,b[l]};} int mid=l+r>>1; return polymul(sol(l,mid),sol(mid+1,r)); } ll ss[N],invs[N]; ll binom(int n,int m){return ss[n]*invs[m]%mod*invs[n-m]%mod;} void f1(){ ss[0]=1; scanf("%d",&n); for(int i=1;i<=n;i++){ ss[i]=ss[i-1]*i%mod; scanf("%d",&b[i]); } invs[n]=pm(ss[n],mod-2); for(int i=n-1;i>=0;i--)invs[i]=invs[i+1]*(i+1)%mod; poly res=sol(1,n); ll ans=0; for(int i=1;i<=n;i++){ ans=(ans+1ll*res[i]*getinv(binom(n,i))%mod)%mod; } printf("%lld\n",ans); } int main(){ int t;scanf("%d",&t); while(t--) f1(); return 0; }