luogu P2303 [SDOi2012]Longge的问题

传送门

\[\sum_{i=1}^{n}\gcd(i,n) \]

考虑枚举所有可能的gcd,可以发现这一定是\(n\)的约数,当\(\gcd(i,n)=x\)时,\(gcd(\frac{i}{x},\frac{n}{x})=1\),可以知道gcd为\(x\)的数的个数就是\(\varphi_{\frac{n}{x}}\)

所以要求的是$$\sum_{d|n}d*\varphi_{\frac{n}{d}}$$

\(\varphi\)的话只要像筛素数那样筛出来救星了

#include<bits/stdc++.h>
#define il inline
#define re register
#define LL long long
#define db double
#define ldb long double
#define eps (1e-7)

using namespace std;
il LL rd()
{
    LL x=0,w=1;char ch=0;
    while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
    return x*w;
}
LL n,prm[20][2],p[10000],tt,tmd,a1;
void d1(int o,LL s)
{
  if(o>tt) {p[++tmd]=s;return;}
  for(int i=0;i<=prm[o][1];i++)
    {
      d1(o+1,s);
      s*=prm[o][0];
    }
}
int main()
{
  n=rd();
  LL sn=sqrt(n),bb=n;
  for(LL i=2;i<=sn&&bb;i++)
    {
      if(bb%i==0)
        {
    	  prm[++tt][0]=i;
    	  while(bb%i==0) bb/=i,++prm[tt][1];
        }
    }
  if(bb>1) prm[++tt][0]=bb,prm[tt][1]=1;
  d1(1,1);
  sort(p+1,p+tmd+1);
  map<LL,LL> phi;
  phi[1]=1,tt=0;
  for(LL i=2;i<=tmd;i++)
    {
      if(phi.find(p[i])==phi.end()) phi[p[i]]=p[i]-1,++tt;
      for(int j=1;j<=tt&&p[i]*prm[j][0]<=n;j++)
        {
    	  phi[p[i]*prm[j][0]]=phi[p[i]]*1ll*(prm[j][0]-1);
    	  if(p[i]%prm[j][0]==0) {phi[p[i]*prm[j][0]]+=phi[p[i]];break;}
        }
    }
  for(LL i=1;i<=tmd;i++) a1=(a1+phi[p[i]]*(n/p[i]));
  printf("%lld ",a1);
  return 0;
}

posted @ 2018-10-11 21:20  ✡smy✡  阅读(133)  评论(3编辑  收藏  举报