【51nod1348】乘积之和

###Description
给出由N个正整数组成的数组A,有Q次查询,每个查询包含一个整数K,从数组A中任选K个(K <= N)把他们乘在一起得到一个乘积。求所有不同的方案得到的乘积之和,由于结果巨大,输出Mod 100003的结果即可。例如:1 2 3,从中任选1个共3种方法,{1} {2} {3},和为6。从中任选2个共3种方法,{1 2} {1 3} {2 3},和为2 + 3 + 6 = 11。

###Solution
f l , r , x ( 0 ≤ x ≤ r − l + 1 ) f_{l,r,x}(0\leq x\leq r-l+1) fl,r,x(0xrl+1)表示区间 [ l , r ] [l,r] [l,r]选了 x x x个的乘积和,可以发现 f l , r f_{l,r} fl,r f l , p f_{l,p} fl,p f p + 1 , r ( l ≤ p < r ) f_{p+1,r}(l\leq p<r) fp+1,r(lp<r)的卷积。
直接分治 N T T NTT NTT即可,选两个模数合并一下答案。

###Code

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fo(i,j,k) for(int i=j;i<=k;++i)
#define fd(i,j,k) for(int i=j;i>=k;--i)
using namespace std;
typedef long long ll;
const int N=5e4+10,P=1e5+3,mo1=998244353,mo2=1004535809;
ll ny1,ny2;
const ll Mo=1002772198720536577ll;
int a[N],fn,mo;
ll f[18][N<<2],g[18][N<<2],w[N<<2];
ll pow(ll x,int y){
	ll b=1;
	for(;y;y>>=1,x=x*x%mo) if(y&1) b=b*x%mo;
	return b;
}
void NTT(ll *a,int fn,int sig){
	int p=0;
	fo(i,0,fn-1){
		if(i<p) swap(a[i],a[p]);
		for(int j=fn>>1;(p^=j)<j;j>>=1);
	}
	for(int m=2;m<=fn;m<<=1){
		int half=m>>1,t=fn/m;
		fo(i,0,half-1){
			int w0=sig>0?w[t*i]:w[fn-t*i];
			for(int j=i;j<fn;j+=m){
				ll u=a[j],v=a[j+half]*w0%mo;
				a[j]=(u+v)%mo,a[j+half]=(u-v+mo)%mo;
			}
		}
	}
	ll ny=pow(fn,mo-2);
	if(sig<0) fo(i,0,fn-1) a[i]=a[i]*ny%mo;
}
ll mul(ll x,ll y,ll k) {
	x%=k,y%=k;
	ll tmp=(ll)((long double)x*y/k+1e-8)*k;
	return (x*y-tmp+k)%k;
}
void fz(int dep,int l,int r){
	if(l==r){
		f[dep][0]=1,f[dep][1]=a[l];
		g[dep][0]=1,g[dep][1]=a[l];
		return;
	}
	int fn,mid=(l+r)>>1;
	for(fn=1;fn<=r-l+2;fn<<=1);
	fz(dep+1,l,mid);
	fo(i,0,fn-1) g[dep][i]=f[dep][i]=f[dep+1][i],f[dep+1][i]=0;
	fz(dep+1,mid+1,r);
	fo(i,0,fn-1) g[dep+1][i]=f[dep+1][i];
	//mo1
	mo=mo1,w[0]=1,w[1]=pow(3,(mo-1)/fn);
	fo(i,2,fn) w[i]=w[i-1]*w[1]%mo;
	NTT(f[dep],fn,1),NTT(f[dep+1],fn,1);
	fo(i,0,fn-1) f[dep][i]=f[dep][i]*f[dep+1][i]%mo,f[dep+1][i]=0;
	NTT(f[dep],fn,-1);
	//mo2
	mo=mo2,w[0]=1,w[1]=pow(3,(mo-1)/fn);
	fo(i,2,fn) w[i]=w[i-1]*w[1]%mo;
	NTT(g[dep],fn,1),NTT(g[dep+1],fn,1);
	fo(i,0,fn-1) g[dep][i]=g[dep][i]*g[dep+1][i]%mo,g[dep+1][i]=0;
	NTT(g[dep],fn,-1);
	//merge
	fo(i,0,fn-1){
		ll t=(mul(f[dep][i],ny1,Mo)+mul(g[dep][i],ny2,Mo))%Mo%P;
		f[dep][i]=t;
	}
}
int main()
{
	mo=mo1,ny1=pow(mo2,mo-2)*mo2;
	mo=mo2,ny2=pow(mo1,mo-2)*mo1;
	int n,q;
	scanf("%d %d",&n,&q);
	fo(i,1,n) scanf("%d",&a[i]),a[i]%=P;
	fz(1,1,n);
	while(q--){
		int x;
		scanf("%d",&x);
		printf("%lld\n",f[1][x]);
	}
}

posted @ 2018-06-28 15:36  sadstone  阅读(68)  评论(0编辑  收藏  举报