最近在组合数学课上学习了欧拉函数,于是到杭电上找了个欧拉函数的基本题目试了一下。
http://acm.hdu.edu.cn/showproblem.php?pid=1286
找到以后发现自己以前就A过这道题,但是当时不知道欧拉函数,用的是枚举法,过是过了,但是时间有点不能看。
这个时间是15MS,希望大神指点如何跑出0MS。
题目的意思很简单,就是让你找到n以内与n互质的数的个数,正好就是欧拉函数的定义。
欧拉函数:
对于正整数n,欧拉函数是小于或等于n中与n互质的数的数量。
φ(x)来表示,如:φ(8)=4,
那么欧拉函数的计算公式为:φ(x) = n*(1-1/p1)*(1-1/p2)*(1-1/p3)...(1-1/pn)
其中n为待求的正整数n,pi为p的质因数,注意质因数只算一次。
φ(x) = 18 * (1 - 1/2) * (1 - 1/3) = 6-------------------(1)
质数可以先用线筛法打表。
编程实现的时候可以放心的做除法,因为从(1)式可以看出,分母都是n的因数,不会产生精度问题。只是注意当n太大的时候的溢出问题。
代码如下:
//
// main.cpp
// HDU1286
//
// Created by 汪之涛 on 15-1-7.
// Copyright (c) 2015年 汪之涛. All rights reserved.
//
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
const int MAX = 32768;
int arr[MAX];
int prime[MAX];
int N,num = 0;
void calPrime()
{
memset(arr,1,sizeof(arr));
for(int i = 2;i < MAX;i++)
{
if(arr[i])
{
int tmp = 2;
while(tmp*i < MAX)
{
arr[tmp*i] = 0;
tmp++;
}
}
}
for(int i = 2;i < MAX;++i)
{
if(arr[i])prime[num++] = i;
}
}
int calres(int n)
{
long long res = n;
for(int i = 0;i < num;++i)
{
if(n%prime[i])continue;
res = res * (prime[i]-1)/prime[i];
}
return (int)res;
}
int main()
{
calPrime();
int cases;
scanf("%d",&cases);
while(cases--)
{
scanf("%d",&N);
cout<<calres(N)<<endl;
}
return 0;
}