题目链接

https://lydsy.com/JudgeOnline/problem.php?id=3512

题解

考虑枚举ii,定义
g(n,m)=i=1mφ(in) g(n,m)=\sum_{i=1}^m \varphi(in)
假设
n=kpkak n=\prod_{k}p_k^{a_k}

n=kpkr=kpkak1 n'=\prod_{k}p_k\\ r=\prod_{k}p_k^{a_k-1}
那么
g(n,m)=ri=1mφ(in) g(n,m)=r\sum_{i=1}^m \varphi(in)
反演得到
g(n,m)=rdnφ(nd)g(d,md) g(n,m)=r\sum_{d|n'}\varphi(\frac{n'}{d})g(d,\lfloor\frac{m}{d}\rfloor)
可以递归求解。

事实上,由于每次递归dnd|n',因此只需要最开始提出rr,后面的rr必定=1=1

代码

#include <map>
#include <cstdio>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

const int maxn=1000000;
const int maxm=100000;
const int mod=1000000007;

int p[maxn+10],prime[maxn+10],cnt,mu[maxn+10],phi[maxn+10],last[maxm+10],sum[maxn+10];

int getprime()
{
  p[1]=phi[1]=mu[1]=1;
  for(int i=2; i<=maxn; ++i)
    {
      if(!p[i])
        {
          prime[++cnt]=i;
          phi[i]=i-1;
          mu[i]=-1;
        }
      for(int j=1; (j<=cnt)&&(i*prime[j]<=maxn); ++j)
        {
          int x=i*prime[j];
          p[x]=1;
          if(i%prime[j]==0)
            {
              mu[x]=0;
              phi[x]=phi[i]*prime[j];
              break;
            }
          mu[x]=-mu[i];
          phi[x]=phi[i]*(prime[j]-1);
        }
    }
  for(int i=1; i<=maxm; ++i)
    {
      if(mu[i])
        {
          for(int j=i; j<=maxm; j+=i)
            {
              last[j]=i;
            }
        }
    }
  for(int i=1; i<=maxn; ++i)
    {
      sum[i]=sum[i-1]+phi[i];
      if(sum[i]>=mod)
        {
          sum[i]-=mod;
        }
    }
  return 0;
}

std::map<int,int> mp;

int getphi(int n)
{
  if(n<=maxn)
    {
      return sum[n];
    }
  if(mp.count(n))
    {
      return mp[n];
    }
  int res=(1ll*n*(n+1)/2)%mod;
  for(int l=2,r; l<=n; l=r+1)
    {
      r=n/(n/l);
      res=(res-1ll*(r-l+1)*getphi(n/l))%mod;
    }
  if(res<0)
    {
      res+=mod;
    }
  return mp[n]=res;
}

struct data
{
  int n,m;

  data(int _n=0,int _m=0):n(_n),m(_m){}

  bool operator <(const data &oth) const
  {
    return (n==oth.n)?(m<oth.m):(n<oth.n);
  }
};

std::map<data,int> mf;

int F(int n,int m)
{
  if(m==0)
    {
      return 0;
    }
  if(n==1)
    {
      return getphi(m);
    }
  data d(n,m);
  if(mf.count(d))
    {
      return mf[d];
    }
  int ans=0;
  for(int i=1; i*i<=n; ++i)
    {
      if(n%i!=0)
        {
          continue;
        }
      ans=(ans+1ll*phi[n/i]*F(i,m/i))%mod;
      if(i*i!=n)
        {
          ans=(ans+1ll*phi[i]*F(n/i,m/(n/i)))%mod;
        }
    }
  return mf[d]=ans;
}

int n,m;

int main()
{
  getprime();
  n=read();
  m=read();
  int ans=0;
  for(int i=1; i<=n; ++i)
    {
      ans=(ans+1ll*(i/last[i])*F(last[i],m))%mod;
    }
  printf("%d\n",ans);
  return 0;
}