51nod1348乘积之和
Posted sadstone
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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}(0leq xleq r-l+1))表示区间([l,r])选了(x)个的乘积和,可以发现(f_{l,r})为(f_{l,p})与(f_{p+1,r}(lleq p<r))的卷积。
直接分治(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
",f[1][x]);
}
}
以上是关于51nod1348乘积之和的主要内容,如果未能解决你的问题,请参考以下文章