欧拉函数和线性筛 学习笔记
参考资料:
oiwik欧拉函数https://oi-wiki.org/math/number-theory/euler/
筛法https://oi-wiki.org/math/number-theory/sieve/
筛法求欧拉函数https://oi-wiki.org/math/number-theory/sieve/#_8
复习时看oiwiki就很好
欧拉函数 φ(n)(推荐看oiwiki)
4条性质:2条自身,1条求自己,1条求n
sqrt n求欧拉函数:
// C++ Version int euler_phi(int n) { int ans = n; for (int i = 2; i * i <= n; i++)//注意不要从1开始否则会死循环, if (n % i == 0) { ans = ans / i * (i - 1); while (n % i == 0) n /= i; } if (n > 1) ans = ans / n * (n - 1);//不要漏 return ans; }
例题:P2303 [SDOI2012] Longge 的问题
题解:想到对于n的一个因数x,会有多少对答案的贡献,即1~n有多少数y,满足gcd(y,n)=x,设t(x)为因数x对答案的贡献,即,令j=i/x,则原式相当于
, 则答案为
。因数可以O(sqrt n)枚举出,φ(x)也可以O(sqrt n)算出,故时间复杂度为O(因数个数 * sqrt n)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstdio> 3 4 using namespace std; 5 6 long long n,ans; 7 8 inline int phi(long long x) 9 { 10 long long ret=x; 11 for(long long i=2;i*i<=x;++i) 12 if(x%i==0) 13 { 14 ret=ret/i*(i-1); 15 while(x%i==0) 16 x/=i; 17 } 18 if(x>1) 19 ret=ret/x*(x-1); 20 return ret; 21 } 22 23 int main() 24 { 25 scanf("%lld",&n); 26 long long i; 27 for(i=1;i*i<n;++i)//完全平方数特殊处理 防重 28 if(n%i==0) 29 ans+=i*phi(n/i)+n/i*phi(i); 30 if(i*i==n) 31 ans+=i*phi(i); 32 cout<<ans; 33 return 0; 34 }
(复杂的式子就是要写下来化简才好嘛)
2、计算一列数1~n的欧拉函数:
O(n)线性筛法(见下)
线性筛:
核心:用每个数尝试以最小质因数的根据筛掉合数。每个合数只会被最小质因数筛掉一次。
对当前i用目前的质数筛,直到当前质数包含在i内后筛完停止。否则再继续筛的话,筛到的合数的最小质因数就不是枚举的质数,而是i内的那个小质因数了。由于目前的质数是扫进来的,故一定小于i,且i的质因数都包含在目前的质数内。复杂度为O(n)。
核心代码:
void GetPrime(int n)//筛到n { memset(isPrime, 1, sizeof(isPrime)); //以“每个数都是素数”为初始状态,逐个删去 isPrime[1] = 0;//1不是素数 for(int i = 2; i <= n; i++) { if(isPrime[i]) Prime[++cnt] = i; for(int j = 1; j <= cnt && i*Prime[j] <= n/*不超上限*/; j++) { isPrime[i*Prime[j]] = 0; if(i % Prime[j] == 0) break; } } }
筛法求欧拉函数:i和p根据整除关系分两类。
搜索
复制