发现 n n 只有 =105 = 10 5 ,我们先考虑 S(n,m)=∑mi=1φ(ni) S ( n , m ) = ∑ i = 1 m φ ( n i ) 怎么求。
先把 n n 分成两部分, n1=∏pi n 1 = ∏ p i ,即所有质因子一次幂的乘积, n2=∏pci−1i n 2 = ∏ p i c i − 1 ,即剩下的。不难发现 φ(n)=φ(n1)∗n2 φ ( n ) = φ ( n 1 ) ∗ n 2 。
#include
#include
#include
#include
#include
#include
#include
#define MP make_pair
#define PB push_back
#define fs first
#define sc second
#define ll long long
#define N 100010
#define U 6000000
#define P 1000000
#define ID(x,y) (x*1234567891+y)
#define up(x,y) x=(x+(y))%mod
using namespace std;
const int mod=1000000007;
bool flag[U+5];
int n,m,pri[U+5],minp[U+5],num,sp[U+5],phi[U+5];
struct hash
{
vector > a[P];
void ins(ll x,ll y)
{
int d=x%P;
a[d].PB(MP(x,y));
}
ll qry(ll x)
{
int d=x%P;
for(int i=a[d].size()-1;i>=0;i--)
if(a[d][i].fs==x) return a[d][i].sc;
return -1;
}
}h;
void getpri()
{
memset(flag,1,sizeof(flag));
flag[1]=0;phi[1]=1;
for(int i=2;i<=U;i++)
{
if(flag[i]) pri[++num]=i,phi[i]=i-1,minp[i]=i;
for(int j=1;j<=num&&i*pri[j]<=U;j++)
{
int v=i*pri[j];
flag[v]=0;minp[v]=pri[j];
if(i%pri[j]==0) {phi[v]=phi[i]*pri[j];break;}
phi[v]=phi[i]*phi[pri[j]];
}
}
}
void fj(int x,int *t)
{
while(x>1)
{
t[++t[0]]=minp[x];
while(x%t[t[0]]==0) x/=t[t[0]];
}
}
ll qphi(int x)
{
if(x<=U) return sp[x];
ll re=((ll)x*(x+1)/2)%mod;
for(int l=2,r;l<=x;l=r+1)
{
r=x/(x/l);
up(re,mod-qphi(x/l)*(r-l+1)%mod);
}
return re;
}
ll S(ll a,ll b)
{
if(!b) return 0;
if(h.qry(ID(a,b))!=-1) return h.qry(ID(a,b));
if(a==1)
{
h.ins(ID(a,b),qphi(b));
return h.qry(ID(a,b));
}
int t[12],w=1;
ll re=0;
t[0]=0;
fj(a,t);
for(int i=1;i<=t[0];i++)
w*=t[i];
for(int i=floor(sqrt(w));i;i--)
if(w%i==0) up(re,S(i,b/i)*phi[w/i]),up(re,S(w/i,b/(w/i))*phi[i]);
re=re*a/w%mod;
h.ins(ID(a,b),re);
return re;
}
int main()
{
getpri();
for(int i=1;i<=U;i++)
sp[i]=(phi[i]+sp[i-1])%mod;
scanf("%d%d",&n,&m);
ll ans=0;
for(int i=1;i<=n;i++)
up(ans,S(i,m));
printf("%lld",ans);
return 0;
}