Link
https://www.lydsy.com/JudgeOnline/problem.php?id=3992
题意
给定一个集合
S
S
S ,
S
S
S 中元素均为小于
M
M
M 的非负整数。(
M
M
M 为质数)
问:用集合中的数能够构造出多少个不同的数列(允许多次使用同一个数),
满足数列中所有数的乘积
≡
x
(
m
o
d
M
)
\equiv x\pmod{M}
≡x(modM)?
x
∈
[
1
,
M
−
1
]
x\in[1,M-1]
x∈[1,M−1]
答案模
1004535809
1004535809
1004535809 。
设计:填了前
i
i
i 个元素,乘积
≡
j
(
m
o
d
M
)
\equiv j\pmod{M}
≡j(modM) 的方案数
f
(
i
,
j
)
f(i,j)
f(i,j)
a
n
s
=
f
(
∣
S
∣
,
x
)
(
m
o
d
p
)
ans=f(|S|,x)\pmod{p}
ans=f(∣S∣,x)(modp)
转移
f
(
i
+
1
,
j
)
=
∑
k
∑
t
=
1
∣
S
∣
f
(
i
,
k
)
[
S
t
≡
k
−
1
j
(
m
o
d
M
)
]
f(i+1,j)=\sum\limits_{k}\sum\limits_{t=1}^{|S|} f(i,k)[S_t\equiv k^{-1}j\pmod{M}]
f(i+1,j)=k∑t=1∑∣S∣f(i,k)[St≡k−1j(modM)]
注意到
M
M
M 是质数就算了,
M
≥
3
M\ge3
M≥3 ……干什么用的?奇素数??
那先不管具体怎么样,我们思考用用原根
f
(
i
,
j
)
f(i,j)
f(i,j) 表示填前
i
i
i 个元素,乘积
≡
g
j
(
m
o
d
M
)
\equiv g^j\pmod{M}
≡gj(modM)
f
(
i
+
1
,
j
)
≡
∑
k
=
0
j
∑
t
=
1
∣
S
∣
f
(
i
,
k
)
[
S
t
≡
g
j
−
k
(
m
o
d
M
)
]
(
m
o
d
p
)
f(i+1,j)\equiv\sum\limits_{k=0}^{j}\sum\limits_{t=1}^{|S|} f(i,k)[S_t\equiv g^{j-k}\pmod{M}]\pmod{p}
f(i+1,j)≡k=0∑jt=1∑∣S∣f(i,k)[St≡gj−k(modM)](modp)
设
G
(
x
)
=
∑
t
=
1
∣
S
∣
[
S
t
≡
g
x
(
m
o
d
M
)
]
(
m
o
d
p
)
G(x)=\sum\limits_{t=1}^{|S|}[S_t\equiv g^{x}\pmod{M}]\pmod{p}
G(x)=t=1∑∣S∣[St≡gx(modM)](modp)
(实际上
G
(
x
)
∈
{
0
,
1
}
G(x) \in \{0,1\}
G(x)∈{0,1} )
但是这样的话
g
0
≡
g
M
−
1
(
m
o
d
M
)
g^0\equiv g^{M-1}\pmod{M}
g0≡gM−1(modM)
所以我们应该设
G
(
x
)
=
∑
i
=
1
∣
S
∣
[
I
g
(
S
t
)
=
x
(
m
o
d
ϕ
(
M
)
)
]
(
m
o
d
p
)
G(x)=\sum\limits_{i=1}^{|S|}[I_g(S_t)=x\pmod{\phi(M)}]\pmod{p}
G(x)=i=1∑∣S∣[Ig(St)=x(modϕ(M))](modp)
f
(
i
+
1
,
j
)
=
∑
k
=
0
j
f
(
i
,
k
)
G
(
j
−
k
)
(
m
o
d
p
)
f(i+1,j)=\sum\limits_{k=0}^{j}f(i,k)G(j-k)\pmod{p}
f(i+1,j)=k=0∑jf(i,k)G(j−k)(modp)
即
f
(
i
+
1
)
≡
f
(
i
)
⊗
G
(
m
o
d
p
)
f(i+1)\equiv f(i)\otimes G\pmod{p}
f(i+1)≡f(i)⊗G(modp)
那么
f
(
N
)
≡
G
N
(
m
o
d
p
)
f(N)\equiv G^{N}\pmod{p}
f(N)≡GN(modp)
注意在卷
G
G
G 卷卷的时候要不停把下标馍馍
(
m
o
d
ϕ
(
M
)
)
\pmod{\phi(M)}
(modϕ(M))
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<cctype>
#include<ctime>
using namespace std;
#define getchar() (frS==frT&&(frT=(frS=frBB)+fread(frBB,1,1<<12,stdin),frS==frT)?EOF:*frS++)
char frBB[1<<12], *frS=frBB, *frT=frBB;
inline void read(int& x)
{
x = 0; char ch = getchar(); bool w = 0;
while (!isdigit(ch)) w |= (ch == '-'), ch = getchar();
while (isdigit(ch)) x = x * 10 + (ch ^ 48), ch = getchar();
w ? (x = -x) : 0;
}
const int MAXN = 16384+16;
const long long p = 1004535809;
inline long long qpow(long long a, long long b, const long long& p)
{
long long ret = 1;
a %= p;
while(b)
{
if (b & 1)
{
ret *= a;
ret %= p;
}
a *= a;
a %= p;
b >>= 1;
}
return ret;
}
const long long g = 3;
int n, m, x, s, Lim = 1, Log;
long long q;
long long Wn[MAXN][2];
int Rev[MAXN];
inline long long Adjust(long long x)
{
x = (x % p) + p;
return (x >= p) ? (x - p) : x;
}
void NTT(long long *a, const bool& Type = 0)
{
for (register int i = 0; i < Lim; ++i) if (Rev[i] > i) swap(a[Rev[i]], a[i]);
register long long x;
for (register int Len, Mid = 1, qwq; Mid < Lim; Mid <<= 1)
{
Len = Mid << 1;
qwq = Lim / Len;
for (register int Pos = 0; Pos < Lim; Pos += Len)
{
for (register int Sub = 0; Sub < Mid; ++Sub)
{
x = Wn[qwq * Sub][Type] * a[Pos + Mid + Sub] % p;
a[Pos + Mid + Sub] = Adjust(a[Pos + Sub] - x);
a[Pos + Sub] = (a[Pos + Sub] + x) % p;
}
}
}
}
int gM;
int PMStack[8005], Ind[8005];
inline void PMSplit(int x)
{
for (register int i = 2; i * i <= x; ++i)
{
if (x % i == 0)
{
PMStack[++PMStack[0]] = i;
while (x % i == 0) x /= i;
}
}
}
inline int GetPrimeRoot(int x, int phi)
{
PMSplit(phi);
register bool flag;
for (register int i = 2; i < x; ++i)
{
flag = 0;
for (register int j = 1; j <= PMStack[0]; ++j)
{
if (qpow(i, phi/PMStack[j], m) == 1)
{
flag = 1;
break;
}
}
if (!flag) return i;
}
}
long long a[MAXN];
long long ta[MAXN], tb[MAXN], inv;
inline void PolyMul(long long *x, long long *y)
{
for (register int i = 0; i < Lim; ++i) ta[i] = x[i] % p;
for (register int i = 0; i < Lim; ++i) tb[i] = y[i] % p;
NTT(ta); NTT(tb);
for (register int i = 0; i < Lim; ++i) ta[i] = ta[i] * tb[i] % p;
NTT(ta, 1);
for (register int i = 0; i < Lim; ++i) ta[i] = ta[i] * inv % p;
for (register int i = 0; i < m-1; ++i) x[i] = (ta[i] + ta[i+m-1]) % p;
//同样要小心自乘的情况
}
long long Ans[MAXN];
void PolyPow(long long *a, int Index)
{
Ans[0] = 1;
while (Index)
{
if (Index & 1)
{
PolyMul(Ans, a);
}
PolyMul(a, a);
Index >>= 1;
}
}
int main()
{
read(n), read(m), read(x), read(s);
gM = GetPrimeRoot(m, m-1);
for (register int i = 0, cur = 1; i < m - 1; ++i) Ind[cur] = i, cur *= gM, cur %= m;
for (register int t, i = 1; i <= s; ++i) read(t), t ? (a[Ind[t]] = 1) : 0;
int mm = m << 1;
while (Lim <= mm) Lim <<= 1, ++Log;
for (register int i = 0; i < Lim; ++i) Rev[i] = (Rev[i>>1]>>1)|((i&1)<<(Log-1));
inv = qpow(Lim, p-2, p);
q = (p - 1) / Lim;
register long long fafa = qpow(g, q, p);
Wn[0][0] = Wn[Lim][0] = Wn[0][1] = Wn[Lim][1] = 1;
for (register int i = 1; i < Lim; ++i) Wn[i][0] = Wn[i-1][0] * fafa % p;
for (register int i = 1; i < Lim; ++i) Wn[i][1] = Wn[Lim-i][0];
PolyPow(a, n);
printf("%lld", Ans[Ind[x]]);
return 0;
}