题目大意:
求
∑ni∑mjϕ(ij)
题解:
orz:Candy?
假装我会了。
以后做数论也要考虑枚举。
update 2018/1/11
过了那么久才填这个坑……
n较小,考虑枚举i,求
sum(n,m)=∑miϕ(ni)
假设
n
是不同质因子的
根据
ϕ(in)=ϕ(i)∗ϕ(nd)d(d=gcd(i,n))
然后用一个骚操作,将 ∑d|nϕ(d) 替换 n
=ϕ(i)∗∑e|dϕ(ne)(d=gcd(i,n))
sum(n,m)=∑inϕ(i)∗∑e|dϕ(ne)(d=gcd(i,n))
=∑e|nϕ(ne)Sum(e,⌊me⌋)
对于 n 不是不同质因子的乘积的,根据
然后记忆化搜索,
n=1
就是
ϕ
的前缀和
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<map>
#include<cmath>
#include<algorithm>
#define pa(i,j) make_pair(i,j)
#define LL long long
using namespace std;
const LL mod=1000000007;
map<int,LL> PHI;
map<pair<int,int>,LL> sum;
int pr=0;
LL sumphi[3000010],prime[3000010],phi[3000010],Left[3000010];
bool v[3000010];
int n,m;
void pre()
{
memset(v,true,sizeof(v));
pr=0;phi[1]=sumphi[1]=1;
for(int i=1;i<=3000000;i++) Left[i]=1LL;
for(int i=2;i<=3000000;i++)
{
if(v[i]) prime[++pr]=(LL)i,phi[i]=(LL)(i-1),Left[i]=i;
for(int j=1;j<=pr&&(LL)i*prime[j]<=3000000;j++)
{
v[i*prime[j]]=false;
if(i%prime[j]==0){phi[i*prime[j]]=phi[i]*prime[j];Left[i*prime[j]]=Left[i];break;}
phi[i*prime[j]]=phi[i]*(prime[j]-1);
Left[i*prime[j]]=Left[i]*prime[j];
}
}
for(int i=2;i<=3000000;i++) sumphi[i]=(phi[i]+sumphi[i-1])%mod;
}
LL findphi(int n)
{
if(n<=3000000) return sumphi[n];
if(PHI[n]) return PHI[n];
LL ans=0;int pos;
for(int i=2;i<=n;i=pos+1)
{
pos=n/(n/i);
ans=(ans+(pos-i+1)*findphi(n/i)%mod)%mod;
}
PHI[n]=((LL)n*(LL)(n+1)/2%mod-ans)%mod;
return PHI[n];
}
LL getphi(int x)
{
if(x<=3000000) return phi[x];
LL ans=(LL)x;int len=sqrt(x);
for(int i=2;i=len;i++)
if(x%i==0)
{
ans=ans/i*(i-1);
while(x%i==0) x/=i;
}
if(x!=1) ans=ans/x*(x-1);
}
LL solve(int n,int m)
{
if(n==1) return findphi(m);
if(sum[pa(n,m)]) return sum[pa(n,m)];
if(m==0) return 0;
int len=sqrt(n);
LL ans=0;
for(int i=1;i<=len;i++)
if(n%i==0)
{
if(i*i!=n){int j=n/i;ans=(ans+getphi(n/j)*solve(j,m/j)%mod)%mod;}
ans=(ans+getphi(n/i)*solve(i,m/i)%mod)%mod;
}
sum[pa(n,m)]=ans;
return ans;
}
int main()
{
pre();
scanf("%d %d",&n,&m);
PHI.clear();sum.clear();
LL ans=0;
for(int i=1;i<=n;i++) ans=(ans+(i/Left[i])*solve(Left[i],m))%mod;
printf("%lld",(ans+mod)%mod);
}