小于n且与n互素的整数个数(欧拉函数)的计算

即计算1~n中与n互素的整数个数

互素就是无法被n整除的数("与p互素"和"不是p的倍数"是等价的)

所以第一种显而易见的方法就是暴力枚举法,但效率太低。

第二种方法用唯一分解定律再运用容斥原理:


分解定律:分为n=p1^a1*p2^a2......pk^ak;


容斥原理:在计数时,要保证无一重复,无一遗漏。为了使重叠部分不被重复计算,在不考虑重叠的情况下,把包含于某内容中的所有对象的数目先计算出来,然后再把计数时重复计算的数目排斥出去,使得计算的结果既无遗漏又无重复,这种计数的方法称为容斥原理。

也即是A∪B∪C=A+B+C-A∩B-B∩C-C∩A+A∩B∩C

于是可以总结出规律:偶数项相加,奇数项相减


所以1~n中与n互素的整数个数= n-p1,p2,p3,p4.....pk的倍数(即-n/p1-n/p2-n/p3...)

                                                      + p1*p2,p1*p3....的倍数(即n/(p1*p2)+n/(p1*p3)....)

                                                       - p1*p2*p3,p1*p2*p4.......的倍数(即-n/(p1*p2*p3)-n/(p1*p2*p4).....)以此类推

这个数算出来就是欧拉函数,即 φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pn);

尝试展开这个公式就会发现与上面那个推导的式子一样,假如从括号中任选一个值出来乘就会发现偶数项为正,奇数项为负,且项与上式一样;


对于求φ(N)只需循环计算得出值就好了


对于求1~n中所有欧拉函数的值不需要依次计算

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
void phi_table(int n,int *phi)
{
	for(int i=1;i<=n;i++) phi[i]=0;
	phi[0]=1;
	for(int i=2;i<=n;i++)
	if(!phi[i])               //每一项i都是素数
	for(int j=i;j<=n;j+=i)     //i的倍数肯定都包含这个素因数 
	{
		if(!phi[j]) phi[j]=j;  //未计算的初始化为j,为了计算式子n*(1-1/p)中的n;
		phi[j]=phi[j]/i*(i-1);
	}
}
int main()
{
	int phi[100+5];
	phi_table(100,phi);
	for(int i=1;i<=100;i++)
	cout<<phi[i]<<' '<<i<<endl;
	return 0;
} 


  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: 这个任务可以使用C语言来实现。具体实现方法如下: 1. 使用一个循环,从m到n遍历所有整数。 2. 对于每个整数,求出它的欧拉函数的值。 3. 如果欧拉函数的值等于1,计数器加1。 4. 如果计数器达到k次,退出循环。 下面是一个示例代码: ``` #include <stdio.h> int euler(int x) { int res = x; for (int i = 2; i * i <= x; i++) { if (x % i == 0) { res = res / i * (i - 1); while (x % i == 0) x /= i; } } if (x > 1) res = res / x * (x - 1); return res; } int main() { int m, n, k, cnt = 0; scanf("%d %d %d", &m, &n, &k); for (int i = m; i <= n; i++) { if (euler(i) == 1) { cnt++; if (cnt == k) break; } } printf("%d\n", cnt); return 0; } ``` 请注意,这个程序只是求出[m,n]之间第k个欧拉函数值为1的整数.如果你需要统计有多少个整数不断对自己取欧拉函数刚好k次结果为1,请自行修改代码. ### 回答2: 要求给定整数m,n,k,需要使用C语言编写程序来完成这个任务。首先,需要明确欧拉函数的定义和性质。 欧拉函数(Euler's totient function)是一个与给定正整数n互素的正整数个数。换句话说,欧拉函数φ(n)表示小于等于n的正整数中与n互素的数的个数。 根据题目要求,我们需要计算在给定的区间[m, n]内,有多少个整数不断对自己取欧拉函数,刚好进行k次操作后的结果为1。 首先,我们可以编写一个函数来计算欧拉函数值。以下是一个简单的欧拉函数计算函数的示例代码: ```c #include <stdio.h> int gcd(int a, int b) { if (b == 0) { return a; } return gcd(b, a % b); } int euler(int n) { int result = 1; for (int i = 2; i < n; i++) { if (gcd(i, n) == 1) { result++; } } return result; } int main() { int m, n, k; printf("请输入m, n, k的值:"); scanf("%d%d%d", &m, &n, &k); int count = 0; for (int i = m; i <= n; i++) { int num = euler(i); int j = 0; while (j < k && num != 1) { num = euler(num); j++; } if (num == 1 && j == k) { count++; } } printf("在区间[%d,%d]中有%d个整数不断对自己取欧拉函数刚好进行%d次操作后的结果为1。\n", m, n, count, k); return 0; } ``` 以上代码实现了一个求解欧拉函数的程序,并且进行了统计满足条件的整数个数。程序中使用了递归的方式来计算最大公约数,然后遍历给定的区间[m, n],依次计算欧拉函数的值,并判断该数经过k次操作后是否等于1。统计满足条件的整数个数,最后输出结果。 希望以上回答对您有所帮助,如有任何疑问,请随时追问。 ### 回答3: 要完成这个任务,首先需要了解欧拉函数和如何计算欧拉函数欧拉函数φ(n)表示小于或等于n的正整数中与n互质的整数个数。根据欧拉函数的定义,一个整数i的欧拉函数可以通过计算与i互质的整数个数得到。即欧拉函数φ(i)可以通过计算1到i之间与i互质的数的个数得到。 题目中给定了三个整数m,n,k,需要找出[m,n]中有多少个整数,经过k次对自身取欧拉函数的操作后得到的结果为1。我们可以使用C来实现这个任务。 首先,我们可以从m到n遍历[m,n]之间的每一个整数i。对于每个整数i,我们可以使用一个循环每次计算i的欧拉函数,并重复k次。如果最后得到的结果为1,则将计数器加一。 下面是使用C语言编写的代码示例: ```c #include <stdio.h> int gcd(int a, int b){ if(b == 0){ return a; } return gcd(b, a%b); } int euler(int n){ int result = 0; for(int i=1; i<=n; i++){ if(gcd(n, i) == 1){ result++; } } return result; } int main(){ int m, n, k; printf("请输入整数m, n, k:"); scanf("%d%d%d",&m,&n,&k); int count = 0; for(int i=m; i<=n; i++){ int num = i; for(int j=0; j<k; j++){ num = euler(num); } if(num == 1){ count++; } } printf("[m,n]中有%d个整数经过%d次取欧拉函数操作后结果为1。\n", count, k); return 0; } ``` 在上面的代码中,我们定义了两个函数gcd和euler。函数gcd用于计算两个整数的最大公约数,函数euler用于计算一个整数欧拉函数。主函数main中,我们首先读取输入的m、n和k,然后使用两个循环计算[m,n]范围内每个整数经过k次取欧拉函数后的结果,并将满足条件的整数计数。最后,输出满足条件的整数个数。 通过运行这段代码,就可以得到[m,n]中有多少个整数经过k次取欧拉函数操作后结果为1的答案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值