Loading

HDU 5829 Rikka with Subset(NTT)

题意

给定 \(n\) 个数 \(a_1,a_2,\cdots a_n\),对于每个 \(K\in[1,n]\) ,求出 \(n\) 个数的每个子集的前 \(K\) 大数的和,输出每个值,对 \(998244353\) 取模。

\(1\leq n \leq 10^5\)

思路

\(K\)\(k\) 时的答案为 \(ans_k\)

\[ans_k=\sum_{i=1}^na_i2^{n-i}\sum_{j=0}^{k-1}{i-1\choose j} \]

\(j\) 为在 \(a_i\) 的左边选了多少个数。定义当\(i<j\)\(\displaystyle{i\choose j}=0\) ,即当 \(n<0\)\(\displaystyle{1\over n!}=0\)

有两个\(\sum\) ,导致难以化简,但是我们发现差分后只有一个 \(\sum\)

\(d_k=ans_k-ans_{k-1}\) ,则有

\[d_k=\sum_{i=1}^na_i2^{n-i}{i-1\choose k-1}\\ d_k=(k-1)!\sum_{i=1}^na_i2^{n-i}(i-1)!\cdot{1\over{(i-k)!}} \]

\(i+k\) 替换 \(k\) ,并化成卷积形式

\[d_{i+k}=(i+k-1)!a_i2^{n-i}(i-1)!\cdot{1\over{(-k)!}} \]

其中 \(i\in[1,n],i+k\in[1,n],k\in[1-n,n-1]\)

\(\displaystyle A_i=a_i2^{n-i}(i-1)!,B_k={1\over{(-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;
}
posted @ 2019-01-15 15:37  Paulliant  阅读(180)  评论(0编辑  收藏  举报