官方题解:首先有等式(xa−1,xb−1)=xgcd(a,b)−1成立,相当于计算∑∑xgcd(a,b)−1 。记s[d]=最大公约数为d的对数,答案∑s[d]∗(xd−1). 先用筛法计算出欧拉函数。把正方形分成上三角和下三角计算,最大公约数为d的数量s[d]=2*(phi[1]+phi[2]+...+phi[n/d])-1,对欧拉函数求一个前缀和,直接枚举最大公约数d复杂度为O(n)。观察s[d]计算公式,可以发现对不同的d,若n/d相同,s[d]不发生变化。根据s[d]分段计算,相同的一段的xd−1可以用等比公式求。复杂度为(n+T√nlogn)
并没有理解分段计算的复杂度。。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
typedef long long LL;
const int N=1000000+10;
const int M=1000000007;
int p[N],phi[N];
LL x,n;
void getp()
{
for (int i=1;i<N;i++)phi[i]=i,p[i]=0;
for (int i=2;i<N;i++)if (!p[i]){
for (int j=i;j<N;j+=i)p[j]=1,phi[j]=phi[j]/i*(i-1);
}
for (int i=2;i<N;i++)phi[i]=(phi[i]+phi[i-1])%M;
for (int i=2;i<N;i++)phi[i]=(phi[i]*2-1)%M;
}
LL RP(LL a,LL b){
LL Ans=1;
for (;b;b>>=1){
if (b&1)Ans=Ans*a%M;
a=a*a%M;
}
return Ans;
}
LL Calc(LL x,LL d,LL nd)
{
LL t1=RP(x,d);
LL t2=RP(x,nd-d+1);
LL t3=RP(x-1,M-2);
return t1*(t2-1+M)%M*t3%M;
}
void work()
{
cin>>x>>n;
if (x==1){
puts("0");
return ;
}
int Ans=0;
for (int d=1;d<=n;){
int u=n/d;
int nd=n/u;
Ans=(1LL*Ans+1LL*Calc(x,d,nd)*phi[u]%M)%M;
d=nd+1;
}
Ans=(1LL*Ans-n*n)%M;
if (Ans<0)Ans+=M;
cout<<Ans<<endl;
}
int main()
{
getp();
int Case;scanf("%d",&Case);
while (Case--)work();
return 0;
}