P6217 简单数论题

这篇博客介绍了如何处理序列中元素与特定数值的最大公约数及最小公倍数的乘积问题。通过预处理序列和利用最大公约数与最小公倍数的性质,可以优化查询效率。在O(1)时间内回答区间乘积并模运算,适用于大规模数据和多次查询。算法使用了质因数分解和前缀积技术,实现了快速计算和空间优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:

给出一个长度为 n 的序列 a,q次询问 ∏ i = l r lcm ⁡ ( a i , x ) \prod\limits_{i=l}^r \operatorname{lcm}(a_i,x) i=lrlcm(ai,x) 的值。

答案对 1 0 9 + 7 10 ^ 9 + 7 109+7取模。

思路:

∏ i = l r l c m ( a i , x ) = ∏ i = l r a i x g c d ( a i , x ) = ∏ i = l r a i x ∏ i = l r g c d ( a i , x ) \begin{aligned} &\prod_{{i=l}}^rlcm(a_i,x)\\ =&\prod_{i=l}^r\frac{a_ix}{gcd(a_i,x)}\\ =&\frac{\prod\limits_{i=l}^ra_ix}{\prod\limits_{i=l}^rgcd(a_i,x)}\\ \end{aligned} ==i=lrlcm(ai,x)i=lrgcd(ai,x)aixi=lrgcd(ai,x)i=lraix
公式上半部分预处理

下半部分
{ x = ∏ i = 1 k p x i q x i a i = ∏ j = 1 k p i j q i j ∏ i = l r g c d ( a i , x ) = ∏ i = l r ∏ j = 1 k p x j m i n ( q i j , q x j ) = ∏ i = 1 k p x i ∑ j = l r m i n ( q j i , q x i ) = ∏ i = 1 k p x i ∑ d = 1 q x i ∑ j = l r [ d ≤ q j i ] = ∏ i = 1 k p x i ∑ d = 1 q x i ∑ j = l r [ p x i d ∣ p x i q j i ] = ∏ i = 1 k p x i ∑ d = 1 q x i ∑ j = l r [ p x i d ∣ a j ] \begin{cases} x&=&\prod_{i=1}^kp_{xi}^{q_{xi}}\\ a_i&=&\prod_{j=1}^kp_{ij}^{q_{ij}} \end{cases}\\ \begin{aligned} &\prod_{i=l}^rgcd(a_i,x)\\ =&\prod_{i=l}^r\prod_{j=1}^kp_{xj}^{min(q_{ij},q_{xj})}\\ =&\prod_{i=1}^kp_{xi}^{\sum\limits_{j=l}^rmin(q_{ji},q_{xi})}\\ =&\prod_{i=1}^kp_{xi}^{\sum\limits_{d=1}^{q_{xi}}\sum\limits_{j=l}^r[d\le q_{ji}]}\\ =&\prod_{i=1}^kp_{xi}^{\sum\limits_{d=1}^{q_{xi}}\sum\limits_{j=l}^r[p_{xi}^d|p_{xi}^{q_{ji}}]}\\ =&\prod_{i=1}^kp_{xi}^{\sum\limits_{d=1}^{q_{xi}}\sum\limits_{j=l}^r[p_{xi}^d|a_j]}\\ \end{aligned} {xai==i=1kpxiqxij=1kpijqij=====i=lrgcd(ai,x)i=lrj=1kpxjmin(qij,qxj)i=1kpxij=lrmin(qji,qxi)i=1kpxid=1qxij=lr[dqji]i=1kpxid=1qxij=lr[pxidpxiqji]i=1kpxid=1qxij=lr[pxidaj]

先预处理出每个 a i a_i ai是哪些 p i j p_{ij} pij的倍数,用数组存下下标,对于一个区间 [ l , r ] [l,r] [l,r],我们只需要求出 x x x的某个贡献 p x j k ( k ∈ ( 1 , q x j ) ) p_{xj}^k(k\in(1,q_{xj})) pxjk(k(1,qxj))

中包含在 [ l , r ] [l,r] [l,r]区间的下标有多少个。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N = 2e5+10;
const int mod = 1e9+7;
ll fac[N];
int p[N], last[N], tot;
bool st[N];
vector<int> pr[N];
void init() {
	fac[0] = last[1] = 1;
	for(int i=2; i<N; i++) {
		if(!st[i]) p[tot++] = i, last[i] = i;
		for(int j=0; j<tot&&1ll*i*p[j]<N; j++) {
			st[i*p[j]] = 1;
			last[i*p[j]] = p[j];
			if(i % p[j] == 0) break;
		}
	}
}
ll qpow(ll x, ll y) {
	ll ans = 1;
	while(y) {
		if(y & 1) ans = ans * x % mod;
		x = x * x % mod;
		y >>= 1;
	}
	return ans;
}
int main() {
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
    freopen("out.txt", "w", stdout);
#endif
	init();
	int n, m, x;
	scanf("%d%d", &n, &m);
	for(int i=1; i<=n; i++) {
		scanf("%d", &x);
		fac[i] = fac[i-1] * x % mod;
		int tmp = x;
		while(tmp != 1) {
			int u = last[tmp], v = 1;
			while(tmp % u == 0) {
				tmp /= u;
				v *= u;
				pr[v].push_back(i);
			}
		}
	}
	int l, r;
	for(int i=1; i<=m; i++) {
		scanf("%d%d%d", &l, &r, &x);
		int tmp = x;
		ll res = 1;
		while(tmp != 1) {
			int u = last[tmp], v = 1, cnt = 0;
			while(tmp % u == 0) {
				tmp /= u;
				v *= u;
				cnt += upper_bound(pr[v].begin(), pr[v].end(), r)-lower_bound(pr[v].begin(), pr[v].end(), l);
			}
			res = res * qpow(u, cnt) % mod;
		}
		printf("%lld\n", fac[r]*qpow(fac[l-1], mod-2)%mod*qpow(x, r-l+1)%mod*qpow(res, mod-2)%mod);
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值