一.前置技能
二.题意及分析
题意:
推导:
这里直说关键结论,结论更详细推导推荐这篇博客
①由GCD性质,
②因为gcd=1,这道题a和b没作用了
左半部分有j与i互素约束,和为n*euler(n)
右半部分N>1,不大于N且和N互素的所有正整数的和为1/2*euler(n)*n (这步当时不会证,gg)
右半部分还要注意加上N==1的情况
④经典杜教筛(还是最裸的),看这篇博客链接--应用三
可以用狄利克雷卷积证明,最后得到
杜教筛常规套路,前半部分平方和公式,n(n+1)(2n+1)/6,后半部分分块求
三.代码
存个取模版杜教筛
但数组空间看情况开,这里开1e7会MLE
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define N 1000010
using namespace std;
typedef long long ll;
template<typename T>inline void read(T &x)
{
x=0;
static int p;p=1;
static char c;c=getchar();
while(!isdigit(c)){if(c=='-')p=-1;c=getchar();}
while(isdigit(c)) {x=(x<<1)+(x<<3)+(c-48);c=getchar();}
x*=p;
}
const int mod=1e9+7;
int inv2,inv6;
bool vis[N];
int mu[N];
ll sum1[N],phi[N];
long long sum2[N];
int cnt,prim[N];
tr1::unordered_map<long long,long long>ansphi;
tr1::unordered_map<int,int>ansmu;
ll ksm(ll x, int y) {
ll res = 1;
while (y) {
if (y & 1)
res = res * x % mod;
x = x * x % mod;
y /= 2;
}
return res;
}
void get(int maxn)
{
phi[1]=mu[1]=1;
for(int i=2;i<=maxn;i++)
{
if(!vis[i])
{
prim[++cnt]=i;
mu[i]=-1;phi[i]=i-1;
}
for(int j=1;j<=cnt&&prim[j]*i<=maxn;j++)
{
vis[i*prim[j]]=1;
if(i%prim[j]==0)
{
phi[i*prim[j]]=phi[i]*prim[j]%mod;
break;
}
else mu[i*prim[j]]=-mu[i],phi[i*prim[j]]=phi[i]*(prim[j]-1+mod)%mod;
}
}
for(int i=1;i<=maxn;i++)sum1[i]=sum1[i-1]+mu[i],sum2[i]=(sum2[i-1]+i*phi[i]%mod)%mod;
}
long long djsphi(long long x)
{
if(x<=1000000)return sum2[x];
if(ansphi[x])return ansphi[x];
long long ans=x%mod*(x+1)%mod*(2*x%mod+1)%mod*inv6%mod;
for(long long l=2,r;l<=x;l=r+1)
{
r=x/(x/l);
//cal(r)-cal(l-1)
//ans-=(r-l+1)*(l+r)%mod*inv2%mod*djsphi(x/l)%mod;
ans-=1ll*((1ll * (r + 1) * r / 2 - 1ll * l * (l - 1) / 2) % mod )*djsphi(x/l)%mod;
ans=(ans+mod)%mod;
}
return ansphi[x]=ans;
}
int main()
{
int t,n,a,b;
read(t);
get(1000000);
inv2=ksm(2,mod-2);
inv6=ksm(6,mod-2);
while(t--)
{
read(n);
read(a);
read(b);
printf("%lld\n",(djsphi(n)-1+mod)%mod*inv2%mod);
}
return 0;
}