发现nn只有,我们先考虑S(n,m)=∑mi=1φ(ni)S(n,m)=∑i=1mφ(ni)怎么求。
先把nn分成两部分,,即所有质因子一次幂的乘积,n2=∏pci−1in2=∏pici−1,即剩下的。不难发现φ(n)=φ(n1)∗n2φ(n)=φ(n1)∗n2。
S(n,m)=n2∑i=1mφ(n1i)=n2∑i=1mφ(n1)φ(i)gcd(n1,i)φ(gcd(n1,i))S(n,m)=n2∑i=1mφ(n1i)=n2∑i=1mφ(n1)φ(i)gcd(n1,i)φ(gcd(n1,i))
然后因为φφ是积性函数,所以当gcd(b,a/b)=1gcd(b,a/b)=1时,φ(a)φ(b)=φ(ab)φ(a)φ(b)=φ(ab),所以
=n2∑i=1mφ(n1gcd(n1,i))φ(i)gcd(n1,i)=n2∑i=1mφ(n1gcd(n1,i))φ(i)∑d|gcd(n1,i)φ(d)=n2∑i=1mφ(n1gcd(n1,i))φ(i)gcd(n1,i)=n2∑i=1mφ(n1gcd(n1,i))φ(i)∑d|gcd(n1,i)φ(d)
这里用∑d|nφ(d)∑d|nφ(d)代替nn是为了去掉的限制,并且和前面的合并。
=n2∑i=1mφ(i)∑d|gcd(n1,i)φ(n1d)=n2∑d|n1φ(n1d)∑i=1⌊md⌋φ(di)=n2∑d|n1φ(n1d)S(d,md)=n2∑i=1mφ(i)∑d|gcd(n1,i)φ(n1d)=n2∑d|n1φ(n1d)∑i=1⌊md⌋φ(di)=n2∑d|n1φ(n1d)S(d,md)
注意到SS中的参数最多只有种,可以记忆化,当n=1n=1的时候就是杜教筛啦。
听说复杂度O(nm−−√+m23)O(nm+m23)。可是还是不太明白求了所有的∑mdi=1φ(i)∑i=1mdφ(i)为什么还是O(m23)O(m23)。。。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<cmath>
#include<vector>
#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<pair<ll,ll> > 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;
}