题解:P6217 简单数论题

P6217 简单数论题题解

题目描述

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

本题思路很多,但先前的大佬们都并不注重代码上的说明,本篇题解着重代码实现。

公式结论

\[\prod_{i=l}^r \operatorname{lcm}(a_i,x) =\frac{\prod_{i=l}^r a_i \times x^{r-l+1}}{\prod_{i=l}^r \operatorname{gcd}(ai,x)} \]

\[\text{令 }x_i=\prod_{i=1}^k p_i^{q_i} \text{,其中 }p_i \text{是质数,} q_i \text{ 是自然数。} \]

\[\prod_{i=l}^r \operatorname{gcd}(ai,x) =\prod_{i=1}^k p_i^{\sum_{t=1}^{q_{i}} \sum_{i=l}^r [p_i^t|a_i]} \]

其中 \(a \mid b\) 是整除,等价于 \(b \bmod a = 0\)\([]\) 指当其中表达式为真时返回 \(1\),否则返回 \(0\),推导过程请看其他大佬。

维护

维护 $\prod_{i=l}^r a_i $ 可用线段树,但码量大,不易写,考虑前缀积。

\[\prod_{i=l}^r a_i =\prod_{i=1}^r a_i \div \prod_{i=1}^{l-1} a_i \]

除以一个数等价于乘这个数的逆元

费马小定理:若 \(p\) 为素数,\(a\) 为正整数,且 \(a、p\) 互质。则有 \(a^{p−1} \equiv 1 \pmod p\)

\(x^{r-l+1}\)快速幂

观察上述分母公式,相当于求区间内集合中每个质数出现的次数,可以分解质因数。分解时考虑线性筛预处理,即代码中 \(w\) 数组。

每个质因数次幂建一个 vector,存 \(a_i\) 的下标,由于分解时有序,找 \(x\) 时二分找就行了。

code

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=2e5+5;
int mod=1e9+7;
int n,q;
int a[N];
int mul[N];
vector<int> v[N];

int w[N];
int g[N],s;
bool f[N];

int qpow(int x,int y){			//快速幂 
	int res=1;
	while(y){
		if(y&1)	res=res*x%mod;
		y>>=1;
		x=x*x%mod;
	}
	return res;
} 

signed main(){
	f[1]=1;						//线性筛 
	for(int i=2;i<N;i++){
		if(!f[i])	g[++s]=i,w[i]=i;
		for(int j=1;j<=s&&i*g[j]<N;j++){
			f[i*g[j]]=1;
			w[i*g[j]]=g[j];
			if(i%g[j]==0)	break;
		}
	}
	
	cin>>n>>q;					//读入 
	for(int i=1;i<=n;i++)
		cin>>a[i];
	
	mul[0]=1;					// 前缀积
	for(int i=1;i<=n;i++)
		mul[i]=mul[i-1]*a[i]%mod;
	
	for(int i=1;i<=n;i++){		//分解质因数 
		int x=a[i];
		while(x>1){
			int t=w[x],p=1;
			while(x%t==0){
				x/=t;
				p*=t;
				v[p].push_back(i);
			}
		}
	}
	
	while(q--){
		int l,r,x;
		cin>>l>>r>>x;
		
		int ans=mul[r]*qpow(mul[l-1],mod-2)%mod;
								//费马小定理:x^(mod-2) 是 x 在 mod 下的逆元
		ans=ans*qpow(x,r-l+1)%mod;
		
		while(x>1){
			int t=w[x],p=1,sum=0;
			while(x%t==0){
				x/=t;
				p*=t;
				sum+=upper_bound(v[p].begin(),v[p].end(),r)-lower_bound(v[p].begin(),v[p].end(),l);
			}
			ans=ans*qpow(qpow(t,sum)%mod,mod-2)%mod;
		}
		cout<<ans<<'\n';
	} 
	return 0;
}

完结撒花

posted @ 2026-01-29 21:50  concert_b  阅读(0)  评论(0)    收藏  举报