BZOJ2818 Gcd
题目链接:https://vjudge.net/problem/HYSBZ-2818
知识点: 欧拉函数、积性函数
解题思路:
对于有序数对 \((x,y)\),若其满足 \(gcd(x,y)=p\)(\(p\)为质数),我们可以将 \(x\) 和 \(y\) 同时除以 \(p\),上式就变成了\(gcd(x',y')=1\),那么对于一个 \(x\) ,满足条件的 \(y\) 的个数为 \(\varphi (x)\) 。对于 \([1,N]\) 中的每一个质数 \(p\),我们可以通过求 \([1,N/p]\) 这个范围内的欧拉函数的总和来求得 \(gcd(x,y) = p\) 的无序数对的个数,考虑到题目中的数对是有序的,所以还需要将无序数对乘二。还有一点是当 \(x\) 和 \(y\) 都是相同的质数时需要特殊处理。
求前 \(n\) 个数的欧拉函数值的算法主要就是利用欧拉函数是积性函数的性质和一条欧拉函数的经典计算式:
\(\varphi(n) = \prod_{i=1}^{k} (p_i-1)p_i^{c_i-1}\).
AC代码:
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 typedef long long LL; 5 const int maxn = 1e7+5; 6 bool check[maxn]; 7 int phi[maxn]; 8 int prime[maxn>>1],tot; 9 10 void init(int N){ 11 phi[1]=1; 12 tot=0; 13 for(int i=2;i<=N;i++){ 14 if(!check[i]){ 15 phi[i]=i-1; 16 prime[tot++]=i; 17 } 18 for(int j=0;j<tot&&(LL)i*prime[j]<=N;j++){ 19 check[i*prime[j]]=true; 20 if(i%prime[j]==0){ 21 phi[i*prime[j]]=phi[i]*prime[j]; 22 break; 23 } else{ 24 phi[i*prime[j]]=phi[i]*(prime[j]-1); 25 } 26 } 27 } 28 } 29 30 int main(){ 31 LL ans=0; 32 int N; 33 scanf("%d",&N); 34 init(N); 35 36 for(int i=0;i<tot;i++){ 37 for(int j=1;j<=N/prime[i];j++) 38 ans+=phi[j]*2; 39 ans--; 40 } 41 printf("%lld\n",ans); 42 return 0; 43 }
“这些年我一直提醒自己一件事情,千万不要自己感动自己。大部分人看似的努力,不过是愚蠢导致的。什么熬夜看书到天亮,连续几天只睡几小时,多久没放假了,如果这些东西也值得夸耀,那么富士康流水线上任何一个人都比你努力多了。人难免天生有自怜的情绪,唯有时刻保持清醒,才能看清真正的价值在哪里。”