找新朋友
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 5518 Accepted Submission(s): 2842
链接: http://acm.hdu.edu.cn/showproblem.php?pid=1286
Problem Description
新年快到了,“猪头帮协会”准备搞一个聚会,已经知道现有会员N人,把会员从1到N编号,其中会长的号码是N号,凡是和会长是老朋友的,那么该会员的号码肯定和N有大于1的公约数,否则都是新朋友,现在会长想知道究竟有几个新朋友?请你编程序帮会长计算出来。
Input
第一行是测试数据的组数CN(Case number,1<CN<10000),接着有CN行正整数N(1<n<32768),表示会员人数。
Output
对于每一个N,输出一行新朋友的人数,这样共有CN行输出。
Sample Input
2
25608
24027
Sample Output
7680
16016
解题思路:
此题是关于欧拉函数的简单数论题,首先我们先来看看欧拉函数(也称 φ函数):
欧拉函数: 对于给定正整数 n ,少于或等于n的数中与n互质的数的数目。
若n是质数p的i次幂,φ(n)=p^i - p^(i-1)=(p-1)*p^(i-1) (解题关键),因为除了p的倍数外,其他数都跟n互质。
设n为正整数,以 φ(n)表示不超过n且与n互素的正整数的个数,称为n的欧拉函数值,这里函数
φ:N→N,n→φ(n) 称为欧拉函数。
欧拉函数是积性函数——若m,n互质,φ(mn)=φ(m)φ(n) [积性函数的形式]。
特殊性质:当n为奇数时,φ(2n)=φ(n), 证明与上述类似
根据欧拉函数,对于给定的 n ,我们总能找到小于 n 的(当 n 为素数时, 等于 n )素数 p1, p2, ··· , pN, 使得
n = (p1 ^ a1) * (p2 ^ a2) * ···· * (pN ^ aN);
所以,
φ(n)=φ(p1 ^ a1) * φ(p2 ^ a2) * ··· * φ(pN ^ aN)
所以,
φ(n) = ((p1 - 1)* p1^(a1 - 1)) * ((p2 - 1)* p2^(a2 - 1)) * ··· * ((pN - 1)* pN^(aN - 1))
首先,我们假设与 n 互质的数(小于 n ) 有 n 个, 事实上它有 φ(n) 个, 我们可以寻找 n 与 φ(n) 的关系来求解:
n / φ(n) = (p1 * p2 * ··· * pN) / ((p1-1) * (p2-1) * ··· *(pN-1))
所以,
φ(n) = (n * (p1-1) * (p2-1) * ··· *(pN-1)) / (p1 * p2 * ··· * pN);
即:
φ(n) = n * ((p1-1) / p1) * ((p2-1) / p2) * ··· * ((pN-1) / pN);
AC代码:
1 #include<iostream> 2 #include<cmath> 3 4 using namespace std; 5 6 int Euler(int n); 7 8 int main() 9 { 10 int cn, n, num; 11 cin >> cn; 12 while(cn--) 13 { 14 cin >> n; 15 num = Euler(n); 16 cout << num << endl; 17 } 18 return 0; 19 } 20 21 int Euler(int n) 22 { 23 int num, i; 24 num = n; 25 for(i = 2; i < (int)sqrt(n*1.0)+1; ++i) 26 { 27 if(!(n % i )) { 28 num = num/i *(i-1); 29 while(!(n % i)) 30 n /= i; 31 } 32 } 33 if(n > 1) 34 num = num/n * (n-1); 35 return num; 36 }