【欧拉函数】集合

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

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

欧拉函数φ:φ(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; 
}  


### 关于欧拉函数的实现与解题思路 #### 一、欧拉函数的核心概念 欧拉函数 \( \phi(n) \) 表示小于等于正整数 \( n \) 中与 \( n \) 互质的数的数量。两个数互质意味着它们的最大公约数为 1。 其定义可以形式化为: \[ \phi(n) = |\{k : 1 \leq k \leq n, gcd(k,n)=1\}| \] 其中,\( gcd(a,b) \) 是指 \( a \) 和 \( b \) 的最大公约数[^1]。 --- #### 二、欧拉函数的性质 以下是欧拉函数的一些重要性质: 1. 如果 \( p \) 是素数,则 \( \phi(p) = p-1 \),因为所有小于 \( p \) 的自然数都与其互质。 2. 若 \( n = p_1^{k_1}p_2^{k_2}\cdots p_m^{k_m} \) (即 \( n \) 可分解为其唯一素因子乘积),则有: \[ \phi(n) = n \cdot \prod_{i=1}^m \left(1-\frac{1}{p_i}\right) \] 3. 对任意整数 \( m \) 和 \( n \),如果 \( gcd(m,n) = 1 \),那么满足加性关系: \[ \phi(mn) = \phi(m)\phi(n) \] 这些性质使得我们可以高效地计算大范围内的欧拉函数。 --- #### 三、欧拉函数的计算方法 ##### 方法一:基于因数分解的方法 通过上述公式可以直接得出如何利用素因子分解来快速求取单个数对应的欧拉函数。具体步骤如下所示: 对于给定的一个整数 \( n \),先找出它的所有不同素因子集合 \( P=\{p_1,p_2,\ldots ,p_k\} \),接着按照下面方式逐步累乘得到最终结果: \[ \phi(n) = n \times \prod _{{p\in P}}{\Bigl (}1-{1 \over p}{\Bigr )} \] 此过程的时间复杂度主要取决于寻找素因子的速度,在合理范围内能够接受。 ```python def euler_phi(n): result = n i = 2 while i * i <= n: if n % i == 0: result -= result // i while n % i == 0: n //= i i += 1 if n > 1: result -= result // n return result ``` 以上代码实现了单独查询某个特定数字对应欧拉函数得功能。 --- #### 四、线性筛法优化批量预处理欧拉函数 当面对大量连续区间上的询问时,采用逐一调用上面提到的独立版效率较低;此时可借助埃氏筛选或者更优美的欧拉筛完成一次性初始化操作后再作答即可达到目的。 下面是使用线性筛的方式预先存储好一定界限以内各位置关联欧拉函数表项的具体做法说明以及相应伪码展示: 初始设定 phi[1]=1 ,其余均置零; 遍历过程中遇到未标记过的当前考察对象x时将其加入候选列表并更新后续可能受影响的位置y=x*p[p_index]处的状态信息直至超出边界为止。 ```python MAXN = int(2e6)+5 phi = list(range(MAXN)) for i in range(2, MAXN): if phi[i]==i: # prime number found for j in range(i, MAXN, i): phi[j]-=(phi[j]//i) print(phi[:20]) #[1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16, 6, 18, 8,...] ``` 这种方法适用于需要频繁访问较小范围的情况下的场景下非常有效率。 --- #### 五、针对题目描述中的解答方案设计 根据所给出的例子来看待输入数据规模较大情形下仍然保持良好性能表现尤为重要因此推荐采取第二种全局规划策略即提前准备好必要素材再按需提取答案最为合适不过啦! 样例如下: 假设我们已经完成了前面提及到的大致一百万级别长度数组构建工作之后就可以轻松应对绝大数常规测试点了。 ```python if __name__=="__main__": import sys input=sys.stdin.read data=input().strip() num=int(data) print(euler_phi(num)) if num<MAXN else None ``` 注意这里为了简化演示忽略了部分细节比如错误捕捉机制等等实际开发当中还是建议补充完善的异常捕获逻辑以便更好地适应各种极端状况哦[^4]! ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值