P5655 基础数论函数练习题 题解

chen_03 Orz!

题意

给定长度为 n 的数组 aQ 次询问 lcm(al,al+1,,ar1,ar),对 109+7 取模。

题解

对于每个右端点,我们维护每个左端点的答案。

具体的,设当前右端点为 m,我们尝试找到数列 bi 使得区间 [i,m] 的答案为 j=imbj,显然 bi|ai

假设我们已求出右端点为 m1 时的数组 b,现在尝试求出右端点为 m 时的数组 b

首先,bm=am。若 j>ibj 都已求出,那么有:

j=i+1mbj=amj=i+1m1bjgcd(am,j=i+1m1bj)

j=imbj=amj=im1bjgcd(am,j=im1bj)

两式相除得:

bi=bigcd(am,j=im1bj)gcd(am,j=i+1m1bj)

X=am,Y=bi,Z=j=i+1m1bj,则:

gcd(am,j=im1bj)gcd(am,j=i+1m1bj)=gcd(X,YZ)gcd(X,Z)

=gcd(Xgcd(X,Z),YZgcd(X,Z))=gcd(Xgcd(X,Z),Y)=gcd(amgcd(am,j=i+1m1bj),bi)

通过上述式子我们已经可以 O(Tn2loga) 求出答案。

si=j=im1bj,注意到 gcd(am,j=i+1m1bj)=gcd(am,si+1) 一定是 am 的约数,且对 1i<jm,有 gcd(am,sj)|gcd(am,si),因此不同的 gcd(am,si) 取值只有 O(loga) 种。

如何快速找到这 O(loga) 个位置来减少计算 gcd 的次数呢?注意到若 gcd(am,si)>gcd(am,si+1),那么一定存在某个质因子 p 在左式中的次数比右式中的高。

pam,si,si+1 中的出现次数分别为 x,y,z,那么 y>z,又因为 min(x,y)>min(x,z),因此 x>z

min(x,y)>z,所以这等价于 (si+1modam)modgcd(am,si)0

因此,用一个变量 tmp 存当前 gcd(am,si) 的值,根据 (si+1modam)modtmp 是否等于 0 可判断出是否需要更新 tmp

总时间复杂度 O(Tn(n+log2a))

Code

#include<bits/stdc++.h>
#define LL long long
#define mod 1000000007
using namespace std;
int n,q,Test_num;
LL tmp,c,tmp1,tmp2;
LL a[302],b[302],s[302];
LL ans[302][302];
inline LL gcd(LL a,LL b)
{
	return b? gcd(b,a%b):a;
}
inline void solve()
{
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;++i)scanf("%lld",&a[i]);
	for(int i=1;i<=n;++i)
	{
		ans[i][i]=(b[i]=a[i])%mod,s[i]=1;
		for(int j=i-1;j;--j)s[j]=((__int128)s[j+1]*b[j])%a[i];
		tmp2=gcd(s[1],a[i]);
		for(int j=1;j<i;++j)if(s[j+1]%tmp2)tmp1=gcd(s[j+1],a[i]),c=tmp2/tmp1,tmp2=tmp1,tmp/=c,b[j]/=c;
		for(int j=i-1;j;--j)ans[j][i]=(ans[j+1][i]*(b[j]%mod))%mod;
	}
	for(int i=1,x,y;i<=q;++i)scanf("%d%d",&x,&y),printf("%lld\n",ans[x][y]);
}
int main()
{
	for(scanf("%d",&Test_num);Test_num--;)solve();
	return 0;
}
posted @   18Michael  阅读(95)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
点击右上角即可分享
微信分享提示