线性筛及线性递推欧拉函数

首先是很常用的线性筛代码:

#define N 1000000
int n, cnt, vis[N+5], prime[N+5];
void sieve() {
    vis[1] = 1;
    for(int i = 2; i <= n; ++i) {
        if(!vis[i]) prime[++cnt] = i;
        for(int j = 1; j <= cnt && i*prime[j] <= n; ++j) {
            vis[i*prime[j]] = 1;
            if(i%prime[j]==0) break;
        }
    }
}

线性筛保证了每个合数只会被它的最小质因子筛掉,所以复杂度是近似\(O(n)\)的。

欧拉函数

定义:对正整数n,欧拉函数是小于或等于n的正整数中与n互质的数的数目(φ(1)=1)。
计算公式:

\(\phi(x)=x\prod\limits_{i=1}^{n}(1-\frac{1}{p_i})\)

\(p_i\)\(x\)的质因子。
性质:欧拉函数是积性函数(即 \(\phi(mn)=\phi(m)\phi(n)\),m,n互质)
我们考虑怎样在线性筛时顺便求出欧拉函数:
1.若 \(vis[i]=1\),说明 \(i\)是质数, \(phi[i]=i-1\)
2.若 \(prime[j]\)整除 \(i\),说明 \(i*prime[j]\)标准分解式中 \(prime[j]\)的次数已经大于 \(1\)了,根据欧拉函数的计算式,不难得出 \(phi[i*prime[j]]=phi[i]*prime[j]\)
3.若 \(prime[j]\)不整除 \(i\),说明 \(i\)\(prime[j]\)互质,又因为 \(prime[j]\)是质数,则 \(phi[i*prime[j]]=phi[i]*phi[prime[j]]\),进而推出 \(phi[i*prime[j]]=phi[i]*(prime[j]-1)\)
我们按照上式把线性筛改造一下就行了:

#define N 1000000
int n, cnt, vis[N+5], prime[N+5], phi[N+5];
void sieve() {
    vis[1] = phi[1] = 1;
    for(int i = 2; i <= n; ++i) {
        if(!vis[i]) prime[++cnt] = i, phi[i] = i-1;
        for(int j = 1; j <= cnt && i*prime[j] <= n; ++j) {
            vis[i*prime[j]] = 1;
            if(i%prime[j]==0) { phi[i*prime[j]] = phi[i]*prime[j]; break; }
            phi[i*prime[j]] = phi[i]*phi[prime[j]];
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/dummyummy/p/9788664.html
今日推荐