[BZOJ2818] gcd - 欧拉函数+筛法

    我们筛出N以内所有的素数,同时求出从1-N所有的欧拉函数值,最后枚举素数累加答案即可。

#include "iostream"
using namespace std;
typedef long long ll;
const int N=10000005;
int n,tmp;
int eular[N],prime[N];
ll sum,esum[N];
void Eular_All(){ ll i,j;
  //筛选从1-n的Eular函数 
  //若 n=ij 且i与j互素 eular(n)= eular(i)*eular(j);
  //若 n为素数 eular(n)=n-1
  //若 n为素数平方数 eular(n)= n-sqrt(n) 
  eular[1]=1;
  for (i=2;i<=n;i++)
  { // 每次可以更新到所有i^2后的答案 
    if (eular[i]==0) // 还没有fill过 
    { prime[++tmp]=i;
      eular[i]=i-1;
      if(i*i<=n)
       eular[i*i]=i*i-i;
    }
    for (j=1;j<tmp&&i*prime[j]<=n;j++) //计算i*prime[j]的答案 
    {
      if(i%prime[j])//互素 
       eular[i*prime[j]]=eular[i]*eular[prime[j]];
      else //i恰为prime[j]的倍数 
       eular[i*prime[j]]=eular[i]*prime[j]; 
    }
  }
  for (i=1;i<=n;i++)
    esum[i]=esum[i-1]+eular[i];
}
int main(){
  cin>>n; int i;
  Eular_All();
  for (i=1;i<=tmp;i++)
    sum += esum[n/prime[i]]*2-1;
  cout<< sum <<endl;
  return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值