题意:
给长度为\(n\)的数列\(a_i\),\(q\)个询问每次给\(k\),问不同方案\(k\)个数乘起来乘积的和。(mod=1e5+4)
思路:
从乘起来的和切入容易想到ntt吧。问题是怎么卷。
ntt,ftt只能解决两个多项式相卷的问题。
因此用分治(二分),可解决问题。
分治是递归的,会存在状态怎么存的问题,这个一定要想清楚?不能一个变量赋值后递归下去又被改了。
这里可以存\(f[i][dep]\)在正常状态上加一维\(O(logn)\)的层数,这样就不会冲突。
然后毒瘤出题人给的是\(100005\)这种坏模数。
我按照题解学写了一下双模数,正常\(10^5\)保证正确应该用三模数才稳妥,这个做法正确的原理是最终的值不超过三个模数的积(相当于准确值没有取模)。
还是有一个坑点是学CRT的漏洞:就是处理出来的余数一定要是最小非负数。之前因为是负数G了好几波。然后先合并出模\(p_0*p_1\)的余数,再去模\(100005\)
模数很大时记得用龟速乘。
code:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=3e5+5;
const int M=21;
const ll mod=100003;
ll val[N],f[N][M],P[]={998244353,1004535809},inv[]={669690699,332747959};
const ll MOD=P[0]*P[1];
ll x[N],y[N],z[N],w[N];
int up,l,rev[N];
ll p;
ll ksm(ll a,ll b) {ll mul=1;for(;b;b>>=1,a=a*a%p)if(b&1)mul=mul*a%p;return mul;}
ll cheng(ll a,ll b) {if(b<0)b=(b+MOD)%MOD;ll sum=0;for(;b;b>>=1,a=(a+a)%MOD)if(b&1)sum=(sum+a)%MOD;return sum;}
void NTT(ll *a,int op) {
for(int i=0;i<up;i++)if(rev[i]>i)swap(a[i],a[rev[i]]);
for(int mid=1;mid<up;mid<<=1) {
ll len=mid<<1,g=ksm((op==-1)?ksm(3,p-2):3,(p-1)/len);
for(int l=0;l<up;l+=len) {
ll GG=1;
for(int i=0;i<mid;i++,GG=GG*g%p) {
int pp=l+i,qq=pp+mid;
ll x=a[pp],y=GG*a[qq];
a[pp]=(x+y)%p;a[qq]=(x-y)%p;
}
}
}
}
void init(int len) {
up=1;l=0;
while(up<=len) {up<<=1;l++;}
for(int i=1;i<up;i++) {rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));}
}
void Mul(ll *a,ll *b) {
NTT(a,-1);
NTT(b,-1);
for(int i=0;i<up;i++) a[i]=a[i]*b[i]%p;
NTT(a,1);
ll i_up=ksm(up,p-2);
for(int i=0;i<up;i++) a[i]=(a[i]*i_up%p+p)%p;
}
int _CDQ(int l,int r,int dep) {
if(l==r) {f[0][dep]=1;f[1][dep]=val[l];return 2;}
int mid=(l+r)>>1,len=r-l+1;
int lL=_CDQ(l,mid,dep+1);
for(int i=0;i<lL;i++) {
f[i][dep]=f[i][dep+1];
}
int lR=_CDQ(mid+1,r,dep+1);
for(int i=0;i<lR;i++) {
y[i]=f[i][dep+1];
}
init(len);
for(int i=0;i<up;i++) {
if(i>=lL) {f[i][dep]=0;}
if(i>=lR) {y[i]=0;}
z[i]=x[i]=f[i][dep];w[i]=y[i];
}
p=P[0];Mul(x,y);
p=P[1];Mul(z,w);
//CRT
for(int i=0;i<up;i++) {
f[i][dep]=(cheng(x[i]*P[1]%MOD,inv[1])+cheng(z[i]*P[0]%MOD,inv[0]))%MOD;
f[i][dep]=(f[i][dep]%mod+mod)%mod;
}
return up;
}
int main() {
// freopen("data.out","w",stdout);
int n,q;scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++){scanf("%lld",&val[i]);}
int wy=_CDQ(1,n,1);
while(q--) {
int k;scanf("%d",&k);
printf("%lld\n",(f[k][1]+mod)%mod);
}
return 0;
}