分析:
这道题与其他题目的最大区别,在于这里变成了累乘,而不是累加。
这样就不能直接用NTT搞了。
所以要转化一下问题:引入原根。
原根的一大性质就是,若对于一个质数p,其一个原根为g
则
g0,g1,g2,……gp−2(mod p)
g
0
,
g
1
,
g
2
,
…
…
g
p
−
2
(
m
o
d
p
)
构成了p的一个既约剩余系(即mod p 的意义下各不相同)。
这样一来,对于每一个值,我们将其映射到g的某个次方,这样一来,每次相乘就是指数相加。
注:0要被忽略。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 20000
using namespace std;
typedef long long ll;
int G=3;
const ll MOD=1004535809;
const int siz=16384;
ll fsp(ll x,int y,ll mod){
ll res=1;
while(y){
if(y&1) res=(res*x)%mod;
x=(x*x)%mod;
y>>=1;
}
return res;
}
void ntt(ll *a,int f,int N){
int i,j,k;
for(i=1,j=0;i<N;i++){
for(int d=N;j^=d>>=1,~j&d;);
if(i<j)
swap(a[i],a[j]);
}
for(i=1;i<N;i<<=1){
ll wn=fsp(G,(MOD-1)/(2ll*i),MOD);
if(f==0)
wn=fsp(wn,MOD-2,MOD);
for(j=0;j<N;j+=i<<1){
ll w=1;
for(k=0;k<i;k++,w=(w*wn)%MOD){
ll x=a[j+k],y=(w*a[i+j+k])%MOD;
a[j+k]=(x+y)%MOD;
a[i+j+k]=(x-y+MOD)%MOD;
}
}
}
if(f==0){
ll inv=fsp(N,MOD-2,MOD);
for(int i=0;i<N;i++)
a[i]=(a[i]*inv)%MOD;
}
}
ll A[MAXN],B[MAXN];
int n,x,m,s;
vector<int> pr;
int find_g(int x){
pr.clear();
int x1=x-1;
for(int i=2;i<=x1;i++)
if(x1%i==0){
pr.push_back(i);
while(x1%i==0)
x1/=i;
}
for(int i=2;i<x;i++){
bool flag=0;
for(int j=0;j<pr.size();j++){
if(fsp(i,(x-1)/pr[j],x)==1)
flag=1;
}
if(flag==0)
return i;
}
}
int tas[MAXN],xx;
int main(){
SF("%d%d%d%d",&n,&m,&xx,&s);
int g=find_g(m);
int sum=1;
for(int i=0;i<m-1;i++){
tas[sum]=i;
sum=sum*g%m;
}
for(int i=0;i<s;i++){
SF("%d",&x);
if(x==0)
continue;
B[tas[x]]=1;
}
A[0]=1;
m--;
ntt(B,1,siz);
while(n){
if(n&1){
ntt(A,1,siz);
for(int i=0;i<siz;i++)
A[i]=A[i ]*B[i]%MOD;
ntt(A,0,siz);
for(int i=m;i<siz;i++){
A[i%m]=(A[i%m]+A[i])%MOD;
A[i]=0;
}
}
for(int i=0;i<siz;i++)
B[i]=B[i]*B[i]%MOD;
ntt(B,0,siz);
for(int i=m;i<siz;i++){
B[i%m]=(B[i%m]+B[i])%MOD;
B[i]=0;
}
ntt(B,1,siz);
n>>=1;
}
PF("%lld",A[tas[xx]]);
}