欧拉函数&最大公约数

  求对于1~n中每个数x在[1,x]区间内和x互质的数的个数

  可以直接暴力枚举,辗转相除gcd(x,y)=1时互质

  辗转相除法复杂度O(logN),所以该方法复杂度O(N^2·logN):

//最大公约数 
#include
#include
using namespace std;
int n,tot;
int gcd(int x,int y){
	if (y==0) return x;
		 else return gcd(y,x%y);
}
int main(){
	freopen("phi.in","r",stdin);
	freopen("phi1.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++){
		int tot=0;
		for (int j=1;j<=i;j++) if (gcd(i,j)==1) tot++;
		printf("%d\n",tot);
	}
	return 0;
}

  对于欧拉函数,phi(x)等于[1,x]区间内和x互质数的个数

  设p1,p2,p3,……,pk是x所有互异质因子,则phi(x)=x·(1-1/p1)·(1-1/p2)·(1-1/p3)·……·(1-1/pk)

  而且phi(x)是个积性函数,当a、b互质时phi(a·b)=phi(a)·phi(b)

  主要还有两个特点:

  1、若 x%y=0 则phi(xy)=phi(x)*y 
  2、若 x%y≠0 则phi(xy)=phi(x)*(y-1) 

  所以可以在线性筛(即欧拉筛法)的过程中直接求phi,复杂度为O(N):

//欧拉函数 
#include
#include
using namespace std;
int phi[100005],prime[100005];
bool vis[100005];
int n,cnt;
int main(){
	freopen("phi.in","r",stdin);
	freopen("phi.out","w",stdout);
	memset(vis,0,sizeof(vis));
	scanf("%d",&n);
	phi[1]=1;
	cnt=0;
	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[prime[j]*i]=1;
			if (i%prime[j]==0){
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			else phi[i*prime[j]]=phi[i]*(prime[j]-1);
		}
	}
	for (int i=1;i<=n;i++) printf("%d\n",phi[i]);
	return 0;
}

【写的有漏洞的,欢迎路过大神吐槽】

  2016/12/22 20:35:41

  Ending.


你可能感兴趣的:(BZOJ,欧拉函数,数论,欧拉函数)