【欧拉函数】集合

给一个正整数,其中,求使得为质数的的个数,

其实挺难看出这题要用欧拉定理做的。

欧拉函数φ:φ(n)表示1 … n中与n互质的整数个数。即:

for(int i=1;i<=n;++i)

    if(gcd(i,n)==1)

        s++;

(先考虑x<y的,最后*2)所以说,如果这道题目改成:求使得=1的个数,那么就可以枚举y,然后s+=φ(y)来得到结果了。当然也可以用前缀和来一步求。

那么怎么把原题和欧拉函数联系起来?

可以发现,若gcd(x,y)=1,那么gcd(x*质数,y*质数)=质数。反过来若gcd(x,y)=质数,那么x,y都能被该质数整除。所以不如枚举[gcd(x,y)=质数]的这个质数,此时gcd(x/质数,y/质数)=1,就又变成欧拉函数了,范围从原来y∈[1,n]变成y/质数∈[1,n/质数]。可以用一个前缀和f[i]一步求。

——————————————————————————————————————————————————————————

分析:对于本题,因为是使得为质数,所以必然要枚举小于等于的质数,那么对于每一个质数,只

     需要求在区间中,满足有序对互质的对数。

 

     也就是说,现在问题转化为:在区间中,存在多少个有序对使得互质,这个问题就简单啦,因为

     是有序对,不妨设,那么我们如果枚举每一个,小于有多少个互素,这正是欧拉函数。所以

     我们可以递推法求欧拉函数,将得到的答案乘以2即可,但是这里乘以2后还有漏计算了的,那么有哪些呢?

     是且为素数的情况,再加上就行了。

#include <iostream>  
#include <string.h>  
#include <stdio.h>  
#include <bitset>  
using namespace std; 
typedef long long LL; 
const int N=10000010; 
bitset<N> prime; 
LL phi[N]; 
LL f[N]; 
int p[N]; 
int k; 
void isprime() {
    k=0; 
    prime.set(); 
    for(int i=2;i<N;i++) {
        if(prime[i]) {
            p[k++]=i; 
            for(int j=i+i;j<N;j+=i) 
                prime[j]=false; 
        }  
    }  
}  
void Oula() {
    for(int i=1;i<N;i++) phi[i]=i; 
    for(int i=2;i<N;i+=2)phi[i] >>= 1; 
    for(int i=3;i<N;i+=2) {
        if(phi[i]==i) {
            for(int j=i;j<N;j+=i) 
                phi[j]=phi[j]-phi[j]/i; 
        }  
    }  
    f[1]=0; 
    for(int i=2;i<N;i++) 
        f[i]=f[i-1]+(phi[i]<<1); //前i个数的欧拉值前缀和 
}  
LL Solve(int n) {
    LL ans=0; 
    for(int i=0;i<k&&p[i]<=n;i++)//枚举质数p[i]
        ans+=f[n/p[i]]+1; //+1是把x=y=p[i]时算上 
    return ans; 
}  
int main() {
    Oula(); 
    isprime(); 
    int n; 
    scanf("%d",&n); 
    printf("%I64d\n",Solve(n)); 
    return 0; 
}  


猜你喜欢

转载自blog.csdn.net/cacyth/article/details/51182867