题意
给定 (n) 个数 (a_1,a_2,cdots a_n),对于每个 (Kin[1,n]) ,求出 (n) 个数的每个子集的前 (K) 大数的和,输出每个值,对 (998244353) 取模。
(1leq n leq 10^5)
思路
设 (K) 为 (k) 时的答案为 (ans_k)
有
[ans_k=sum_{i=1}^na_i2^{n-i}sum_{j=0}^{k-1}{i-1choose j}
]
(j) 为在 (a_i) 的左边选了多少个数。定义当(i<j) 时 (displaystyle{ichoose j}=0) ,即当 (n<0) 时 (displaystyle{1over n!}=0)
有两个(sum) ,导致难以化简,但是我们发现差分后只有一个 (sum)
设 (d_k=ans_k-ans_{k-1}) ,则有
[d_k=sum_{i=1}^na_i2^{n-i}{i-1choose k-1}\
d_k=(k-1)!sum_{i=1}^na_i2^{n-i}(i-1)!cdot{1over{(i-k)!}}
]
用 (i+k) 替换 (k) ,并化成卷积形式
[d_{i+k}=(i+k-1)!a_i2^{n-i}(i-1)!cdot{1over{(-k)!}}
]
其中 (iin[1,n],i+kin[1,n],kin[1-n,n-1])
设 (displaystyle A_i=a_i2^{n-i}(i-1)!,B_k={1over{(-k)!}})
(d_{i+k}=(i+k-1)A_iB_k)
处理出 (A,B) 两多项式,进行卷积求解即可。
代码
#include<bits/stdc++.h>
#define FOR(i,x,y) for(int i=(x),i##END=(y);i<=i##END;++i)
#define DOR(i,x,y) for(int i=(x),i##END=(y);i>=i##END;--i)
typedef long long ll;
using namespace std;
const int P=998244353,g=3;
const int N=1<<17|5;
namespace Maths
{
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
void exgcd(ll a,ll b,ll &x,ll &y)
{
if(!b){x=1,y=0;return;}
exgcd(b,a%b,y,x),y-=a/b*x;
}
ll Pow(ll a,ll p,ll P)
{
ll res=1;
for(;p>0;p>>=1,(a*=a)%=P)if(p&1)(res*=a)%=P;
return res;
}
ll inv(ll a,ll P){ll x,y;exgcd(a,P,x,y);return (x%P+P)%P;}
};
using namespace Maths;
namespace _NTT
{
const int g=3,P=998244353;
int A[N<<1],B[N<<1];
int w[N<<1],r[N<<1];
void NTT(int *a,int op,int n)
{
FOR(i,0,n-1)if(i<r[i])swap(a[i],a[r[i]]);
for(int i=2;i<=n;i<<=1)
for(int j=0;j<n;j+=i)
for(int k=0;k<i/2;k++)
{
int u=a[j+k],t=(ll)w[op==1?n/i*k:n-n/i*k]*a[j+k+i/2]%P;
a[j+k]=(u+t)%P;
a[j+k+i/2]=(u-t)%P;
}
}
void multiply(int *a,int *b,int *c,int n1,int n2)
{
int n=1;
while(n<n1+n2-1)n<<=1;
FOR(i,0,n1-1)A[i]=a[i];
FOR(i,0,n2-1)B[i]=b[i];
FOR(i,n1,n-1)A[i]=0;
FOR(i,n2,n-1)B[i]=0;
FOR(i,0,n-1)r[i]=(r[i>>1]>>1)|((i&1)*(n>>1));
w[0]=1,w[1]=Pow(g,(P-1)/n,P);
FOR(i,2,n)w[i]=(ll)w[i-1]*w[1]%P;
NTT(A,1,n),NTT(B,1,n);
FOR(i,0,n-1)A[i]=(ll)A[i]*B[i]%P;
NTT(A,-1,n);
int I=inv(n,P);
FOR(i,0,n1+n2-2)c[i]=((ll)A[i]*I%P+P)%P;
}
};
int A[N],B[N],C[N<<2];
int fac[N],c[N],S;
int n,m;
int main()
{
fac[0]=1;FOR(i,1,N-1)fac[i]=(ll)fac[i-1]*i%P;
while(~scanf("%d",&n))
{
FOR(i,0,n)scanf("%d",&c[i]);
scanf("%d",&m);
S=0;
while(m--)
{
int x;
scanf("%d",&x);
S-=x;
if(S<0)S+=P;
}
FOR(i,0,n)A[i]=(ll)c[i]*fac[i]%P;
FOR(i,-n,0)B[i+n]=Pow(S,-i,P)*inv(fac[-i],P)%P;
_NTT::multiply(A,B,C,n+1,n+1);
FOR(i,0,n)printf("%lld ",(C[i+n]*inv(fac[i],P)%P+P)%P);
puts("");
}
return 0;
}