看起来很厉害的题
然而想到原根的话这题就成sb题了
因为模M为质数,所以一定存在原根,所以 [0,M−2] 内可以建立与 [1,M−1] 一一对应的关系。通过原根就可以把原本的乘法变成了指数上的加法。
然后因为它是个数列,很容易想到,也很显然地,可以构造这个数列的生成函数, xi 的系数表示对应项为i的时候的方案数。
总之后面就是很水了,就是个快速幂+NTT的事。
但是做NTT的时候要注意,因为大于M-2后的都会同余回前面,所以要合并回去。(注意不是M-1!!!)
时间复杂度 O(mlognlogm)
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i = a , _ = b ; i <= _ ; i ++)
#define per(i,a,b) for(int i = a , _ = b ; i >= _ ; i --)
#define For(i,a,b) for(int i = a , _ = b ; i < _ ; i ++)
#define maxm 8007
inline int rd() {
char c = getchar();
while (!isdigit(c)) c = getchar() ; int x = c - '0';
while (isdigit(c = getchar())) x = x * 10 + c - '0';
return x;
}
typedef long long ll ;
typedef int arr[maxm];
arr ans , f , idx , _p;
int n , m , X , S , ptt;
namespace NTT{
const int P = 1004535809;
const int G = 3;
const int MAXN = 32767;
int A[MAXN] , B[MAXN] , wn[MAXN] , rev[MAXN];
int N , len;
inline int mul(int a , int b) { return (ll) a * b % P ; }
inline int Pow(int a , int b) {
int t = 1;
while (b) {
if (b & 1) t = mul(t , a);
a = mul(a , a) , b >>= 1;
}
return t;
}
void init(int n , int m) {
for (N = 1 , len = 0 ; N <= n + m ; N <<= 1 , len ++) ;
For (i , 1 , N) rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (len - 1));
wn[0] = 1; int g = Pow(G , (P - 1) / N);
For (i , 1 , N) wn[i] = mul(wn[i - 1] , g);
}
void ntt(int*a , int n , int v) {
For (i , 0 , n) if (i < rev[i]) swap(a[i] , a[rev[i]]);
for (int i = 1 , s = 2 ; s <= n ; s <<= 1 , i ++) {
int wm = wn[1 << (len - i)];
for (int k = 0 ; k < n ; k += s) {
int w = 1;
For (j , 0 , s / 2) {
int t = mul(w , a[k + j + s / 2]) , u = a[k + j];
a[k + j] = (u + t) % P , a[k + j + s / 2] = ((u - t) % P + P) % P;
w = mul(w , wm);
}
}
}
if (v == -1) {
int invN = Pow(n , P - 2);
For (i , 0 , n) a[i] = mul(a[i] , invN);
}
}
void conv(int*a , int*b , int*c , int m) {
For (i , 0 , N) A[i] = 0;
For (i , 0 , N) B[i] = 0;
For (i , 0 , m) A[i] = a[i];
For (i , 0 , m) B[i] = b[i];
ntt(A , N , 1) , ntt(B , N , 1);
For (i , 0 , N) A[i] = mul(A[i] , B[i]);
reverse(wn + 1 , wn + N);
ntt(A , N , -1);
rep (i , m , (m - 1) << 1)
(A[i - m] += A[i]) %= P;
For (i , 0 , m) c[i] = A[i];
}
};
inline int mul(int a , int b) { return (ll) a * b % m ; }
inline int Pow(int a , int b) {
int t = 1;
while (b) {
if (b & 1) t = mul(a , t);
a = mul(a , a) , b >>= 1;
}
return t;
}
inline int getPR() {
int t = m - 1;
rep (i , 2 , t) if (t % i == 0) {
_p[++ ptt] = i;
while (t % i == 0) t /= i;
}
for (int i = 2;;i ++) {
bool p = 1;
rep (j , 1 , ptt) if (Pow(i , (m - 1) / _p[j]) == 1) {
p = 0;
break;
}
if (p) return i;
}
}
void input() {
n = rd() , m = rd() , X = rd() , S = rd();
int pr = getPR() , g = 1;
For (i , 0 , m - 1) {
idx[g] = i;
g = mul(g , pr);
}
rep (i , 1 , S) {
int x = rd();
if (!x) continue;
f[idx[x]] = 1;
}
}
void solve() {
NTT::init(m , m);
ans[0] = 1;
while (n) {
if (n & 1) NTT::conv(ans , f , ans , m - 1);
NTT::conv(f , f , f , m - 1);
n >>= 1;
}
printf("%d\n" , ans[idx[X]]);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.txt" , "r" , stdin);
#endif
input();
solve();
return 0;
}