题解 P6217【简单数论题】
Daniel13265
·
·
题解
# 题意
给出正整数序列 $a$,多次给出 $l,r,x$ 询问 $\prod_{i=l}^r\operatorname{lcm}(a_i,x)$。
# 分析
观察到
$$\prod_{i=l}^r\operatorname{lcm}(a_i,x)=\frac{x^{r-l+1}\prod_{i=l}^ra_i}{\prod_{i=l}^r\gcd(a_i,x)}$$
明显 $x^{r-l+1}\prod_{i=l}^ra_i$ 可以维护前缀积并使用快速幂求出,于是我们只需要求 $\prod_{i=l}^r\gcd(a_i,x)$ 的值即可。
如果将 $a_i$ 和 $x$ 分别作质因数分解:
$$\begin{aligned}a_i&=\prod_{j=1}^kp_j^{q_{ij}}\\x&=\prod_{j=1}^kp_j^{q_{xj}}\end{aligned}$$
其中 $p_j$ 表示第 $j$ 个质数,$q\in\mathbb N$。那么有
$$\begin{aligned}\prod_{i=l}^r\gcd(a_i,x)&=\prod_{i=l}^r\prod_{j=1}^kp_j^{\min(q_{ij},q_{xj})}\\&=\prod_{i=1}^kp_i^{\sum_{j=l}^r\min(q_{ji},q_{xi})}\\&=\prod_{i=1}^kp_i^{\sum_{t=1}^{q_{xi}}\sum_{j=l}^r[t\le q_{ji}]}\\&=\prod_{i=1}^kp_i^{\sum_{t=1}^{q_{xi}}\sum_{j=l}^r\left[p_i^t\small|\scriptsize p_i^{q_{ji}}\right]}\\&=\prod_{i=1}^kp_i^{\sum_{t=1}^{q_{xi}}\sum_{j=l}^r\left[p_i^t\small|\scriptsize a_j\right]}\end{aligned}$$
所以我们需要分别对每一个能够整除 $x$ 的质数正整数幂,求出它能够整除 $a_l,a_{l+1},\ldots,a_r$ 中的多少个数,将底数相同的幂的个数相加后快速幂求积即为需要求的部分。
如果线性筛预处理小于 $\sqrt x$ 的质数,那么枚举 $p_i$ 的复杂度为
$$\mathcal O\left(\pi\left(\sqrt x\right)\right)\leq\Theta\left(\frac{\sqrt x}{\log\sqrt x}\right)=\Theta\left(\frac{\sqrt x}{\log x}\right)$$
设能整除一个数 $x$ 的所有质数正整数幂形成的集合为 $\operatorname{PP}(x)$。考虑到对于任意质数 $p\ge2$,有
$$\big|\operatorname{PP}(x\times p)\big|=\big|\operatorname{PP}(x)\big|+1$$
因而
$$\mathcal O\left(\big|\operatorname{PP}(x)\big|\right)=\mathcal O(\log x)$$
因此求出 $\operatorname{PP}(x)$ 的总复杂度为
$$\Theta\left(\frac{\sqrt x}{\log x}\right)+\mathcal O(\log x)=\Theta\left(\frac{\sqrt x}{\log x}\right)$$
可以先对于每一个 $a_i$ 求出 $\operatorname{PP}(a_i)$,之后将每一个质数的正整数幂与包含它的集合对应。这样,对于每一个询问的 $x$,可以在 $\mathcal O(\log n)$ 的时间复杂度内二分查找到 $l,r$ 在能够被整除 $x$ 的一个质数正整数幂整除的 $a_i$ 的下标 $i$ 的集合中的位置,进一步计算出该质数正整数幂在 $\operatorname{PP}(a_l),\operatorname{PP}(a_{l+1}),\ldots,\operatorname{PP}(a_r)$ 中出现的次数。
对每一个质数的正整数幂作二分的时间复杂度都是 $\mathcal O(\log n)$,共有 $\mathcal O(\log x)$ 个这样的质数正整数幂,故此部分的复杂度为 $\mathcal O\left(\log x\log n\right)$。从而得到这个做法的总空间复杂度为 $\mathcal O(\sqrt a+n\log a)$,总时间复杂度为
$$\Theta\left(n\frac{\sqrt a}{\log a}\right)+\mathcal O\left(q\pi\left(\sqrt a\right)\right)+\mathcal O\left(q\log x\log n\right)\leq\Theta\left(n\frac{\sqrt a}{\log a}+q\frac{\sqrt a}{\log a}+q\log x\log n\right)$$
如果认为 $n,q,a_i,x\sim N$,则总复杂度为 $\Theta\left(\frac{N\sqrt N}{\log N}\right)\sim\Theta\left(\frac{\sqrt N}{\log N}\right)\sim\mathcal O(N\log N)$。
更优的做法是在线性筛的时候记录筛去每一个数的质数,这个质数就一定是该数的最小质因子。于是对于任意一个数,可以通过不断除以它的最小质因子来得到它的所有的质因子。由于每一次除都这个数都要至少减少一半,所以利用这个方法求 $\operatorname{PP}(x)$ 的时间复杂度是 $\mathcal O(\log x)$。总空间复杂度为 $\mathcal O(\max(a,x)+n\log a)$,总时间复杂度为
$$\mathcal O\left(\max(a,x)+n\log a\right)+\mathcal O\left(q\log x\right)+\mathcal O\left(q\log x\log n\right)=\mathcal O\left(\max(a,x)+n\log a+q\log x\log n\right)$$
如果认为 $n,q,a_i,x\sim N$,则总复杂度为 $\mathcal O\left(N\log N\right)\sim\mathcal O\left(\log^2N\right)\sim\mathcal O(N\log N)$。
# 参考代码
```cpp
mul[0] = 1;
for (int i = 1; i <= n; ++i) {
int t = read();
mul[i] = mul[i - 1] * t % P;
while (~-t) {
const int &p = fir[t];
int tmp = 1;
while (!(t % p)) {
t /= p;
tmp *= p;
vc[tmp].push_back(i);
}
}
}
while (q--) {
const int &l = read(), &r = read(), &x = read();
int t = x;
long long res = 1ll;
while (~-t) {
const int &p = fir[t];
int tmp = 1, tot = 0;
while (!(t % p)) {
t /= p;
tmp *= p;
tot += upper_bound(vc[tmp].begin(), vc[tmp].end(), r) - lower_bound(vc[tmp].begin(), vc[tmp].end(), l);
}
res = res * qpow(p, tot) % P;
}
cout << (mul[r] * qpow(mul[l - 1] * res % P, P - 2) % P * qpow(x, r - l + 1) % P) << '\n';
}
```