T1
T2 小R的箱子
T3 绯红之王
题目大意:
已知数列$a$,求$\sum\limits_{i=1}^n {a_i}^k$
思路:
很久以前讲过的题,调了一年才搞出来
首先设$f_k=\sum\limits_{i=1}^n {a_i}^k$ , $g_k$表示对于所有$C_n^k$种选择的方法,$g_k=$所有方法内各个数相乘的和
例如数列中有四个数$a,b,c,d$ 则
$g_0=1$
$g_1=a+b+c+d$
$g_2=ab+ac+ad+bc+bd+cd$
$g_3=abc+abd+acd+bcd,g_4=abcd$
我们可以发现
$f_2=f_1 * g_1 - 2g_2$
$f_3=f_2 * g_1 - f_1* g_2 + 3g_3$
$f_4=f_3*g_1-f_2*g_2+f_1*g_3-4g_4$
发现下标为偶数的$g$都变成了其相反数,而且这是一个$f_0$在变化的分治$NTT$形式
那么我们将$f_0$设为0,在$cdq$到$l==r$时,再加上这个$n*g_n$贡献
现在考虑如何计算$g$数组,因为$g_i$是齐次轮换对称式 可以通过计算两部分再合并
例如$h_0=1,h_1=a+b+c,h_2=ab+ac+bc,h_3=abc$
$t_0=1,t_1=d+e+f,t_2=de+df+ed,t_3=def$
则$g_0=h_0*t_0=1$
$g_1=h_0*t_1+h_1*t_0$
$g_2=h_0*t_2+h_1*t_1+h_2*t_0$
$......$
这样可以维护一个类似线段树的结构来计算$g$,即一开始每个点有一个自己的多项式$1,a_i$
然后一层一层往上合并,计算出$g$后再用分治$NTT$来计算$f$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cstdlib> 5 #include<cmath> 6 #include<algorithm> 7 #include<queue> 8 #include<vector> 9 #include<map> 10 #include<set> 11 #define ll long long 12 #define db double 13 #define inf 2139062143 14 #define MAXN 800100 15 #define MOD 998244353 16 #define rep(i,s,t) for(register int i=(s),i##__end=(t);i<=i##__end;++i) 17 #define dwn(i,s,t) for(register int i=(s),i##__end=(t);i>=i##__end;--i) 18 #define ren for(register int i=fst[x];i;i=nxt[i]) 19 #define pb(i,x) vec[i].push_back(x) 20 #define pls(a,b) (1LL*a%MOD+b%MOD+MOD)%MOD 21 #define mns(a,b) (1LL*a%MOD-b%MOD+MOD)%MOD 22 #define mul(a,b) ((ll)(1LL*(a))%MOD*(b)%MOD)%MOD 23 using namespace std; 24 inline int read() 25 { 26 int x=0,f=1;char ch=getchar(); 27 while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();} 28 while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();} 29 return x*f; 30 } 31 int n,rev[MAXN],l2[MAXN],pw[MAXN],A[MAXN],B[MAXN],aa[MAXN]; 32 int g[MAXN],f[MAXN]; 33 vector<int> vec[MAXN]; 34 int q_pow(int bas,int t,int res=1) 35 { 36 for(;t;bas=mul(bas,bas),t>>=1) 37 if(t&1) res=mul(res,bas);return res; 38 } 39 void ntt(int *a,int n,int f) 40 { 41 rep(i,0,n-1) if(i<rev[i]) swap(a[i],a[rev[i]]); 42 for(int i=1;i<n;i<<=1) 43 { 44 int wn=pw[i<<1];if(f==-1) wn=q_pow(wn,MOD-2); 45 for(int j=0;j<n;j+=i<<1) 46 { 47 int w=1,x,y; 48 for(int k=0;k<i;k++,w=mul(w,wn)) 49 x=a[k+j],y=mul(a[i+j+k],w),a[j+k]=pls(x,y),a[i+j+k]=mns(x,y); 50 } 51 } 52 if(f==1) return ;int nv=q_pow(n,MOD-2); 53 rep(i,0,n-1) a[i]=mul(a[i],nv); 54 } 55 void solve(int *a,int *b,int lmt) 56 { 57 ntt(a,lmt,1);ntt(b,lmt,1);rep(i,0,lmt-1) a[i]=mul(a[i],b[i]); 58 ntt(a,lmt,-1); 59 } 60 void Div(int l,int r,ll lmt=0) 61 { 62 if(l==r) return ;int mid=(l+r)>>1,lg; 63 Div(l,mid);Div(mid+1,r);lg=l2[r-l+1]+1,lmt=1<<lg; 64 rep(i,0,lmt-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(lg-1)),A[i]=B[i]=0; 65 rep(i,0,vec[l].size()-1) A[i]=vec[l][i]; 66 rep(i,0,vec[mid+1].size()-1) B[i]=vec[mid+1][i]; 67 solve(A,B,lmt); 68 vec[l].clear();vec[mid+1].clear(); 69 rep(i,0,lmt-1) vec[l].push_back(A[i]); 70 } 71 void cdq(int l,int r) 72 { 73 if(l==r) {f[l]=pls(f[l],mul(g[l],l));return ;} 74 int mid=l+r>>1,lmt=r-l+1;cdq(l,mid); 75 int t=l2[lmt]+1;lmt=1<<t; 76 rep(i,0,lmt-1) rev[i]=(rev[i>>1]>>1)|((i&1)<<(t-1)),A[i]=B[i]=0; 77 rep(i,l,mid) A[i-l]=f[i];rep(i,1,r-l) B[i-1]=g[i]; 78 solve(A,B,lmt);rep(i,mid+1,r) f[i]=pls(f[i],A[i-l-1]); 79 cdq(mid+1,r); 80 } 81 int main() 82 { 83 n=read();rep(i,1,n) aa[i]=read();rep(i,2,n<<2) l2[i]=l2[i>>1]+1; 84 rep(i,1,n<<2) pw[i]=q_pow(3,(MOD-1)/i); 85 rep(i,1,n) vec[i].push_back(1),vec[i].push_back(aa[i]); 86 Div(1,n);rep(i,0,n) g[i]=vec[1][i]; 87 rep(i,0,n) if(!(i&1)) g[i]=-g[i]; 88 cdq(0,n);rep(i,1,n) printf("%d\n",f[i]); 89 }
原文地址:https://www.cnblogs.com/yyc-jack-0920/p/10539856.html