题目大意
求([1,n])中满足(n|x^m-x)的(x)的个数,其中(n)以(n=p_1 p_2 p_3 ... p_c)的形式给出。
(c leq 50, p_i leq 10^4, mleq 10^9)
解析
这题关键是(n)的每个质因子都只有一个。
将方程(x^m-x equiv 0 (mod n))变为下列方程:
({x_i}^m-x_i equiv 0 (mod p_i) 1leq i leq c)
列出同余方程组:
(x equiv x_i (mod p_i))
(n=p_1 p_2 p_3 ... p_c),根据中国剩余定理,在([1,n])内(x)有且仅有一个解,即一组合法的(x_i)唯一对应一个(x)。
而将(x mod p_i)又能唯一对应一组(x_i),因此(x)的解数就是合法(x_i)的组数,即各合法(x_i)的解数相乘。
问题是如何快速求({x_i}^m-x_i equiv 0 (mod p_i))的解数。
众所周知(x^m)是个积性函数,我们只需要求出([1,p_i])内每个质数的(m)次幂,便可以用线性筛求出每个(x_i)的(m)次幂,然后暴力判断,就能AC了,但是有更快的方法。
利用了这样一个结论:(x^m-x equiv 0 (mod p))的解数为(gcd(m-1,p-1)+1)。
证明是这样的:
(p)是一个质数,因此(p)必定有原根(g),根据原根的性质,([1,p-1])内每个数都能用(g^k mod p)表示,原方程可变为:
根据费马小定理:
变形:
令(y=gcd(m-1,p-1)),得到:
这时(gcd(frac{m-1}{y},frac{p-1}{y})=1),所以(frac{p-1}{y} | k),(k)是在([0,p-2])中的,因此(k)可以取到(frac{p-1}{y})的([0,y-1])倍,所以合法的(k)有(y)个,对应了合法的(x=g^k)也有(y)个,但是(x=p)也是可以的,所以共(y+1)个合法的(x)。结论得证。
然后就能以(O(sum logp_i))的复杂度解决了,快到飞起。
Code
#include <cstdio>
typedef long long ll;
const ll P = 998244353;
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
int T, c;
ll p, m, ans;
int main()
{
freopen("division.in", "r", stdin);
freopen("division.out", "w", stdout);
scanf("%*d%d", &T);
while (T--)
{
scanf("%d%lld", &c, &m);
ans = 1;
for (int i = 1; i <= c; i++) scanf("%lld", &p), ans = ans * (gcd(m - 1, p - 1) + 1) % P;
printf("%lld
", ans);
}
return 0;
}