P6217 简单数论题

题目传送门

题意:给出一个长度为 n 的序列 aq 次询问 i=lrgcd(ai,x)n,V2×105

数论好题

套路地,将 lcm 换成 gcd,问题即求 i=lraixgcd(ai,x),分子是好求的,现在问题即求 gcd(ai,x)

很多 gcd 的题目都是将 x 分解质因数,这道题同样如此,设 x=p1c1p2c2pmcm,考虑每个质因子 pi 的贡献,那么 pi 在指数上的贡献应该是 j=1cicount(pij),其中 count(x) 表示 lrx 的倍数的个数。容易想到可以使用主席树维护。

具体地,将每个 ai 分解质因数,将 pi,pi2,,pici 从小到大插入主席树。询问时对 x 分解质因数,对 pij 依次查询即可。

时间复杂度 O((n+q)(V+log2V))

#include<bits/stdc++.h>
#define LL long long
using namespace std;

const int N=2e5+10,M=8e7+10,MOD=1e9+7;

int n,q,a[N],b[N];
int prime[N],v[N],tot;
int rt[N],pt;

void prework()
{
	for(int i=2; i<=2e5; i++)
	{
		if(!v[i])
		{
			v[i]=i;
			prime[++tot]=i;
		}
		for(int j=1; j<=tot; j++)
		{
			if(prime[j]>v[i] || prime[j]>2e5/i)
				break;
			v[i*prime[j]]=prime[j];
		}
	}
}

struct SegmentTree
{
	int lc,rc,dat;
	#define lc(x) tree[x].lc
	#define rc(x) tree[x].rc
	#define dat(x) tree[x].dat
}tree[M];

void build(int &p,int l,int r)
{
	if(!p)
		p=++pt;
	if(l==r)
		return dat(p)=0,void();
	int mid=(l+r)>>1;
	build(lc(p),l,mid);
	build(rc(p),mid+1,r);
}

void insert(int &p,int pre,int l,int r,int pos,int v)
{
	p=++pt;
	tree[p]=tree[pre];
	if(l==r)
		return dat(p)+=v,void();
	int mid=(l+r)>>1;
	if(pos<=mid)
		insert(lc(p),lc(pre),l,mid,pos,v);
	else
		insert(rc(p),rc(pre),mid+1,r,pos,v);
}

int ask(int p,int pre,int l,int r,int pos)
{
	if(!p)
		return 0;
	if(l==r)
		return dat(p)-dat(pre);
	int mid=(l+r)>>1;
	if(pos<=mid)
		return ask(lc(p),lc(pre),l,mid,pos);
	return ask(rc(p),rc(pre),mid+1,r,pos);
}	

void divide(int x,int id)
{
	int pre=rt[id-1],now=0;
	for(int i=1; i<=tot && prime[i]<=sqrt(x); i++)
	{
		int res=1;
		while(x%prime[i]==0)
		{
			x/=prime[i];  res*=prime[i];
			insert(now,pre,1,2e5,res,1);
			pre=now;  now=0;
		}
	}
	if(x!=1)
		insert(now,pre,1,2e5,x,1),pre=now,now=0;
	rt[id]=pre;
}

int ksm(int x,int y)
{
	int res=1;
	while(y)
	{
		if(y&1)
			res=1LL*res*x%MOD;
		x=1LL*x*x%MOD;
		y>>=1;
	}
	return res;
}

int main()
{
	prework();

	scanf("%d%d",&n,&q);  b[0]=1;
	for(int i=1; i<=n; i++)
	{
		scanf("%d",&a[i]);
		b[i]=1LL*a[i]*b[i-1]%MOD;
		divide(a[i],i);
	}

	while(q--)
	{
		int l,r,x,xx,ans=1;
		scanf("%d%d%d",&l,&r,&x);  xx=x;
		for(int i=1; i<=tot && prime[i]<=sqrt(x); i++)
		{
			int res=1;
			while(x%prime[i]==0)
			{
				x/=prime[i];  res*=prime[i];
				ans=1LL*ans*ksm(prime[i],ask(rt[r],rt[l-1],1,2e5,res))%MOD;
			}
		}
		if(x!=1)
			ans=1LL*ans*ksm(x,ask(rt[r],rt[l-1],1,2e5,x))%MOD;
		ans=1LL*b[r]*ksm(b[l-1],MOD-2)%MOD*ksm(xx,r-l+1)%MOD*ksm(ans,MOD-2)%MOD;

		printf("%d\n",ans);
	}

	return 0;
}
posted @   xishanmeigao  阅读(6)  评论(0编辑  收藏  举报
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示