关于欧拉函数
(我就当我学会了杜教筛
传送门:
http://duxyz.github.io/solution/2014/04/03/DZY-Loves-Math-4/
好神啊!!
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
#define ll long long
int n,m;
const ll Mod=1000000007;
const int Maxl=4000007;
const int Con=4000000;
char c;
inline void read(int &a)
{
a=0;do c=getchar();while(c<'0'||c>'9');
while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();
}
ll exgcd(ll a, ll b, ll& x, ll& y)
{
if(b == 0)
{
x = 1, y = 0;
return a;
}
ll d = exgcd(b, a%b, x, y);
ll temp = x;
x = y;
y = temp - a/b*y;
return d;
}
struct Chain
{
int x,y;
ll ans;
Chain *next;
Chain(){next=NULL;}
}*Head[Maxl];
Chain Cache[Con];
int Res=0;
inline Chain *NChain(){return Cache+Res++;}
inline ll P(int x,int y)
{return (x*Mod+y)%Maxl;}
inline void Insert(int x,int y,ll ans,int Pla)
{
Chain *tp=NChain();
tp->x=x,tp->y=y,tp->ans=ans,tp->next=Head[Pla];
Head[Pla]=tp;
}
ll Ans;
inline bool find(int x,int y,Chain *Tp)
{
if(!Tp)return false;
if((Tp->x^x)|(Tp->y^y))
return find(x,y,Tp->next);
Ans=Tp->ans;
return true;
}
ll w;
const
int maxn=100001;
bool Check[maxn];
int prime[maxn],Mu[maxn];
ll Fai[maxn],Sum[maxn];
int t;
ll S(int n,int m)
{
t++;
// if(n>m)swap(n,m);
int Pl;
if(!m)return 0;
if(m==1)return Fai[n];
if(find(n,m,Head[Pl=P(n,m)]))
return Ans;
ll ans=0;
if(n==1)
{
int last=2,i=2;
while(i<=m)
{
last=m/(m/i)+1;
ans-=(last-i)*S(1,m/i)%Mod; ans%=Mod; i=last; } ans+=(m*(m+1ll)%Mod)*w%Mod; } else { int t=sqrt(n),sp,i; for(i=1;i<t;i++) if(n%i==0) ans+=Fai[sp=n/i]*S(i,m/i),ans+=Fai[i]*S(sp,m/sp),ans%=Mod;
if(t*t==n)
ans+=Fai[t]*S(t,m/t); else if(n%t==0) ans+=Fai[sp=n/t]*S(t,m/t),ans+=Fai[t]*S(sp,m/sp);
}
ans=(ans%Mod+Mod)%Mod;
Insert(n,m,ans,Pl);
return ans;
}
int tot;
int Pre[maxn];
inline ll Calc(int n,int m)
{
int i,j;
ll Ans=0;
if(Mu[n]==0)
{
i=Pre[n];
ll x,y;
exgcd(i,Mod,x,y);
Ans=(n*S(i,m)%Mod)*x%Mod;//break;
}
else
Ans=S(n,m);
return Ans;
}
int main()
{
int i,j;
ll r;
exgcd(2,Mod,w,r);
ll k;
for(i=2;i<maxn;i++)
{
if(!Check[i])prime[++tot]=i,Mu[i]=1,Fai[i]=i-1,Pre[i]=i;
for(j=1;j<=tot;j++)
{
k=prime[j]*i;
if(k>=maxn)break;
if(i%prime[j]==0){Fai[k]=Fai[i]*prime[j]%Mod;Pre[k]=Pre[i],Check[k]=true,Mu[k]=0;break; }
Fai[k]=Fai[i]*Fai[prime[j]]%Mod,Mu[k]=Mu[i],Check[k]=true;
if(Mu[k])Pre[k]=k;
else Pre[k]=Pre[i];
}
}
for(i=2;i<maxn;i++)
if(Mu[i]) for(j=i;j<maxn;j+=i)
if(!Mu[j])Pre[j]=i;
Fai[1]=1;
Mu[1]=1;
for(i=1;i<maxn;i++)
Sum[i]=(Sum[i-1]+Fai[i])%Mod;
int n,m;read(n),read(m);
ll Ans=0,tp;
if(n>m)swap(n,m);
for(i=1;i<=n;i++)
Ans+=Calc(i,m),Ans%=Mod;
printf("%lld\n",(Ans+Mod)%Mod);
return 0;
}