前言
富榄好劲啊!
题目大意
TL做法
为了方便,下面的L都用M代替。
显然可以分开每个质数来讨论。
枚举一个pc,所带了的贡献是(pc)(m−⌊mpc+1⌋)n−(m−⌊mpc⌋)n
为什么?很简单,LCM包含pc表示p的指数至少有一个是c,且不能超过c。
容斥一发,就是指数都不超过c-指数都不超过c-1。
指数不超过c,那么必须不能存在一个因数是pc+1。
于是得到了TM算法。
更快一些
我们沿用上面的算法,但我们只处理根号M以内的质数。
而对于大于根号M的质数,它们的指数都是1,因此可以根据m除以它们的值分块。
#include<cstdio>
#include<cmath>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const int maxm=5000000+10;
int pri[maxm],sum[maxm];
bool bz[maxm];
int i,j,k,l,t,n,m,ans,top,mo,ca,b;
void prepare(){
sum[1]=1;
fo(i,2,5000000){
sum[i]=sum[i-1];
if (!bz[i]){
pri[++top]=i;
sum[i]=(ll)sum[i]*i%mo;
}
fo(j,1,top){
if ((ll)i*pri[j]>5000000) break;
bz[i*pri[j]]=1;
if (i%pri[j]==0) break;
}
}
}
int quicksortmi(int x,int y,int mo){
if (!y) return 1;
int t=quicksortmi(x,y/2,mo);
t=(ll)t*t%mo;
if (y%2) t=(ll)t*x%mo;
return t;
}
int main(){
freopen("pupil.in","r",stdin);freopen("pupil.out","w",stdout);
scanf("%d%d",&mo,&ca);
prepare();
while (ca--){
ans=1;
scanf("%d%d",&n,&m);
b=floor(sqrt(m));
fo(i,1,top){
if (pri[i]>b) break;
j=1;
while ((ll)j*pri[i]<=m){
j*=pri[i];
t=quicksortmi(m-m/((ll)j*pri[i]),n,mo-1)-quicksortmi(m-m/j,n,mo-1);
t=(t%(mo-1)+mo-1)%(mo-1);
ans=(ll)ans*quicksortmi(j,t,mo)%mo;
}
}
i=b+1;
while (i<=m){
j=m/(m/i);
t=quicksortmi(m,n,mo-1)-quicksortmi(m-m/i,n,mo-1);
t=(t%(mo-1)+mo-1)%(mo-1);
l=(ll)sum[j]*quicksortmi(sum[i-1],mo-2,mo)%mo;
ans=(ll)ans*quicksortmi(l,t,mo)%mo;
i=j+1;
}
printf("%d\n",ans);
}
}

本文介绍了一种关于质数贡献的算法实现,该算法通过枚举质数并使用容斥原理来解决特定数学问题。文章详细阐述了算法的推导过程,并提供了C++代码示例,包括快速幂运算及质数筛法。

被折叠的 条评论
为什么被折叠?



