BZOJ3512: DZY Loves Math IV

关于欧拉函数
(我就当我学会了杜教筛
传送门:
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;
}

你可能感兴趣的:(BZOJ3512: DZY Loves Math IV)