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

分析

考虑莫队。

S=lcm(al,al+1,al+2,,ar1)。则对于新加进来的 ar,有:

     lcm(al,al+1,al+2,,ar1,ar)=lcm(S,ar)=S×argcd(S,ar)

很容易发现,S 在不取模的情况下会爆 __int128,所以不能这么搞。

考虑从 arlcm(al,al+1,al+2,,ar1,ar) 的贡献。 令 ar 的贡献为 br,则:

br=argcd(i=lr1bi,ar)

然后答案就是 i=lrbi

删除不好搞,用回滚即可。复杂度是 O(Tn2n) 的。

【关于卡常】

注意到 gcd(a,b)=gcd(amodb,b)。那么在算 i=lr1bi 的时候,我们就可以将其对 ar 取模,保证乘积不会爆 longlong。

在暴力求乘积的时候,如果当前的乘积是 ar 的倍数,直接退出循环即可。在正常卡常的基础上加上这个就能过了。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define re register
#define il inline
#define pii pair<int,int>
#define x first
#define y second
#define gc getchar()
#define rd read()
#define debug() puts("------------")

namespace yzqwq{
	il ll read(){
		ll x=0;
		int f=1;char ch=gc;
		while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc;}
		while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=gc;
		return x*f;
	}
	il int qmi(int a,int b,int p){
		int ans=1;
		while(b){
			if(b&1) ans=ans*a%p;
			a=a*a%p,b>>=1;
		}
		return ans;
	}
	il auto max(auto a,auto b){return (a>b?a:b);}
	il int min(int a,int b){return (a<b?a:b);}
	il ll gcd(ll a,ll b){
		return !b?a:gcd(b,a%b);
	}
	il int lcm(int a,int b){
		return a/gcd(a,b)*b;
	}
	il void exgcd(int a,int b,int &x,int &y){
		if(!b) return x=1,y=0,void(0);
		exgcd(b,a%b,x,y);
		int t=x;
		x=y,y=t-a/b*x;
		return ;
	}
	mt19937 rnd(time(0));
}
using namespace yzqwq;

const int N=305;
const ll p=1e9+7;
struct node{
	int l,r,id;
}Q[N];
int n,q,len;
ll a[N],ans[N];
ll b_[N],b[N];
ll S,S_,s;

il int get(int x){
	return (x-1)/len+1;
}
il bool cmp(node a,node b){
	if((a.l-1)/len!=(b.l-1)/len) return a.l<b.l;
	return a.r<b.r;
}
ll mul(ll a,ll b,ll m){
    ll t=a*b-(ll)((long double)a/m*b)*m;
    return t<0?t+m:(t>=m?t-m:t);
}

il void solve(){
	n=rd,q=rd,len=sqrt(n),S=1;
	for(re int i=1;i<=n;++i) a[i]=rd;
	for(re int i=1;i<=q;++i) Q[i]={rd,rd,i};
	sort(Q+1,Q+q+1,cmp);
	int l=1,l_,r=0,lst_bk=0;
	for(re int i=1;i<=q;++i){
		if(get(Q[i].l)==get(Q[i].r)){
			S_=1;
			for(re int j=Q[i].l;j<=Q[i].r;++j){
				s=1;
				for(re int k=Q[i].l;k<j;++k){
					s=mul(s,b_[k],a[j]);
					if(!s) break;
				}
				b_[j]=a[j]/gcd(a[j],s);
				S_=(S_*(b_[j]%p))%p;
			}
			ans[Q[i].id]=S_;
			continue;
		}
		if(lst_bk!=get(Q[i].l)){
			lst_bk=get(Q[i].l);
			l=min(lst_bk*len,n)+1,r=l-1;
			S=1;
		}
		while(r<Q[i].r){
			++r,s=1;
			for(re int k=l;k<r;++k){
				s=mul(s,b[k],a[r]);
				if(!s) break;
			}
			b[r]=a[r]/gcd(a[r],s);
			S=(S*(b[r]%p))%p;
		}
		S_=S,l_=l;
		while(l_>Q[i].l){
			--l_,s=1;
			for(re int k=l_+1;k<=r;++k){
				s=mul(s,b[k],a[l_]);
				if(!s) break;
			}
			b[l_]=a[l_]/gcd(a[l_],s);
			S_=(S_*(b[l_]%p))%p;
		}
		ans[Q[i].id]=S_;
	}
	for(re int i=1;i<=q;++i) printf("%lld\n",ans[i]);
	return ;
}

signed main(){
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	int t=rd;while(t--)
	solve();
	return 0;
}
posted @   harmis_yz  阅读(29)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性
点击右上角即可分享
微信分享提示