欧拉函数问题
来源:互联网 发布:ip2780清零软件 编辑:程序博客网 时间:2024/06/05 16:19
对于这题,做过好久了,但是重新翻出来的时候,脑袋又一脸懵逼了,看不懂自己的代码,自己默默的琢磨了一个晚上,还问了朋友。
题意:求解n以内与n不互质的数的个数
现在我来梳理下我那个晚上到底发生了什么。。。。。
刚开始,看到这题,我想的是,求解不互质个数=n-互质的个数
那这题就转换成求解互质的个数。
无奈当时数学不好啊,好气啊。
求解互质那第一步要先求出n的质因数,这个好办,我素数筛选下用数组存起来就好了。
然后求解互质个数,我暴力for一下,枚举n以内的数能不能整除这些素数
以下是这个思路的代码:
#include<iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include<vector>#include<math.h>#define N 32770using namespace std;typedef long long LL;bool prime[N];int isprime[N],num=0;vector<int> ans;void getprime(){ long long i,j,t; for(i=2;i<=N-5;i++) { if(!prime[i]) { isprime[++num]=i; for(j=2;(t=i*j)<=N-5;j++) { prime[t]=true; } } }}int main(){ getprime(); int T; scanf("%d", &T); while(T--){ ans.clear(); int n; scanf("%d", &n); for(int i=1; i<=num; i++){ int x = isprime[i]; if(x>n) break; if(n%x==0) ans.push_back(x); } int answer=0; for(int i=1; i<n; i++){ bool flag=false; for(int j=0; j<(int)ans.size(); j++){ int x=ans[j]; if(i%x==0){ flag=true; break; } } if(!flag) answer++; } printf("%d\n", answer); }}
然而这个出现了一个问题,我两层for的时间复杂度极高,这样会不会超时呢?有什么更好的办法呢?
然后我去苦坑数学,我翻,我翻,我问,我问。。。
最后我知道了这个问题是欧拉函数。
是我们伟大的欧拉发现的!
对正整数n,欧拉函数是小于等于n的数中与n互质的数的数目。此函数以其首名研究者欧拉命名(Euler'so totientfunction),它又称为Euler's totient function、φ函数、欧拉商数等。 例如φ(8)=4,因为1,3,5,7均和8互质。
通式: φ(N)=N*(1-1/P1)*(1-1/P2)*...*(1-1/Pm)
其中p1, p2……pm为N的所有质因数,N是不为0的整数。
而我们从整数分解那里已经知道一个整数n可以分解为N=p1^a1*p2^a2……pm^am
代入得,φ(N)==p1^(a1-1)*(p1-1)*p2^(a2-1)*(p2-1)……pm^(am-1)*(pm-1)
还不懂的可以去看看这个:http://baike.baidu.com/link?url=IsY7joVqDMTYl1iHfJpiRMI0x-opH0ALhO3SFhxvXl07kS37wDvBnhnB52Gaj232sVhjYSD5wvyjdj8QjPfnW4Wuo3wkikHN7e3q35yTDOaTqeQcGJNnk6cwrPhPBMl9
那么,问题自然而然简单了,我们只要求出它分解之后的底数以及幂就行了,哈哈
下面有两种写法,你们自己看有啥区别吧~
1、正儿八经的写法
#include <iostream> #include <cmath> using namespace std; #define MAXI 20 struct yinshu { int di; int mi; }; struct Div { int xiangshu; int xdi[MAXI]; int xmi[MAXI]; }; Div getpN(int m); void vout(Div pN); yinshu getOne(int yin,int& m); int main() { int ncase,n,i; cin>>ncase; Div pN; while(ncase--) { cin>>n; pN=getpN(n); vout(pN); } return 0; } Div getpN(int m) { int i,j; Div pans; yinshu x; if(m<2) { pans.xdi[0]=1; pans.xmi[0]=0; pans.xiangshu=0; return pans; } i=2; j=0; for(i=2;i*i<=m;i++) { if(m%i==0) { x=getOne(i,m); pans.xdi[j]=x.di; pans.xmi[j]=x.mi; j++; } } if(m>1) { pans.xdi[j]=m; pans.xmi[j]=1; j++; } pans.xiangshu=j; return pans; } void vout(Div pN) { int i,j; int ans=1; for(i=0;i<pN.xiangshu;i++) { for(j=1;j<=pN.xmi[i]-1;j++) { ans*=pN.xdi[i]; } ans*=(pN.xdi[i]-1); } cout<<ans<<endl; } yinshu getOne(int yin,int& m) { yinshu x; x.di=yin; x.mi=0; while(m%yin==0) { x.mi++; m/=yin; } return x; }
2、 思路大概一样啊,其实我也不是很清楚当时就这么做的,到现在也没怎么看懂,
如果你们看懂了好心人可以在评论区告诉我,thank you !
#include <iostream> using namespace std; #define MAXI 20 int fix(int n); int Solve(int n);int main() { int T,n; cin>>T; while(T--){ cin>>n; cout<<n-Solve(n)<<endl; } return 0; }int fix(int n){ int ans=n; int i; for(i=2;i*i<=n;i++){ 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; } int Solve(int n){ int cnt=0;int i; for(i=1;i*i<=n;i++){ if(n%i==0){ if(i>=2) cnt+=fix(n/i); if((n/i)!=i && (n/i)>=2) cnt+=fix(i); } } return cnt; }
- 欧拉函数问题
- BZOJ 2705 - 经典问题 欧拉函数
- BZOJ2705[Longge的问题] 欧拉函数
- 利用欧拉函数解决最大公约数相关问题
- [BZOJ 2705][SDOI 2012]Longge的问题(欧拉函数)
- [BZOJ2480]SDOI2012 Longge的问题|欧拉函数
- BZOJ2705 [SDOI2012]Longge的问题(欧拉函数)
- hdoj 2588 GCD 【欧拉函数 问题转换】
- [欧拉函数]Bzoj2705 Longge的问题[SDOI2012]
- 【bzoj2705】【sdoi2012】【longge的问题】【欧拉函数】
- 【bzoj2705】[SDOI2012]Longge的问题 欧拉函数
- 2705: [SDOI2012]Longge的问题 欧拉函数
- BZOJ_P2705 [SDOI2012]Longge的问题(数论+欧拉函数)
- 2705: [SDOI2012]Longge的问题|欧拉函数
- bzoj--2705--Longge的问题(欧拉函数)
- HYSBZ - 2705 Longge的问题 (欧拉函数)
- BZOJ 2705 Longge的问题(欧拉函数)
- [BZOJ2705] [SDOI2012] Longge的问题 - 欧拉函数
- jQuery中表格全选反选demo
- BZOJ1503: [NOI2004]郁闷的出纳员
- 学生信息处理系统 王朝
- 系统升级时启用保留个人设置
- java数据结构----B树
- 欧拉函数问题
- 一个有趣的二维码生成库Qart
- 对称方阵
- 详解Android中回调机制与RecyclerView的Item点击事件实现
- 关于观察者模式和apply 还有 call 的深入研究
- 建造者模式介绍
- MATLAB数据精度处理
- 死锁问题
- spring声明式事务管理(基于注解)