Description
描述
For given integer N (1<=N<=10^4) find amount of positive numbers not greater than N that coprime with N. Let us call two positive integers (say, A and B, for example) coprime if (and only if) their greatest common divisor is 1. (i.e. A and B are coprime iff gcd(A,B) = 1).
对于给定的整数N(1<=N<=10^4)求不大于N并且与N互素的正整数的个数。我们称两个正整数(例如A、B)互素,但且仅当它们的最大公约数为1。(即gcd(A,B)=1)
Input
输入
Input file contains integer N.
输入文件包含整数N。
Output
输出
Write answer in output file.
将答案输出在输出文件上。
Sample Input
样例输入
9
Sample Output
样例输出
6
Analysis
分析
我首先想到的是欧拉函数(varphileft(N ight)),后来发现数据量并不是特别的大,所以又用暴力做了一遍,也AC了。
这道题目的重点在于欧拉函数(varphileft(N ight))的求法,现总结如下:
欧拉函数(varphileft(N ight)):小于等于N且与N互素的正整数的个数。
欧拉函数据有如下性质:
-
(varphi left ( 1 ight )=1)
-
(varphi left ( N ight )=Ncdotprod_{p|N}{left (frac{p-1}{p} ight )}),其中(p)为素数
-
(varphi left ( p^{k} ight ) = p^{k}-p^{k-1}=left(p-1 ight )cdot p^{k-1}),其中(p)为素数
-
(varphi left ( mn ight )=varphi left ( m ight )cdot varphi left ( n ight )),其中(gcd{left ( m,n ight )}=1)
根据第2个式子我们就可以求出欧拉函数。
基本思路:首先置(varphileft(N ight)=N),然后枚举(N)的素因子(p),将(p)的整数倍的欧拉函数(varphi left ( kcdot p ight ))置(varphi left ( kcdot p ight )=varphi left ( kcdot p ight )cdotleft (frac{p-1}{p} ight ))即可。
基本代码如下:
#include <iostream> using namespace std; const int MAX = 1024; int N; int p[MAX], phi[MAX]; int main() { cin >> N; for(int i = 1; i <= N; i++) // 初始化 { p[i] = 1; phi[i] = i; } p[1] = 0; // 1不是素数 for(int i = 2; i <= N; i++) // 筛素数 { if(p[i]) { for(int j = i * i; j <= N; j += i) { p[j] = 0; } } } for(int i = 2; i <= N; i++) // 求欧拉函数 { if(p[i]) { for(int j = i; j <= N; j += i) // 处理素因子p[i] { phi[j] = phi[j] / i * (i - 1); // 先除后乘,防止中间过程超出范围 } } } cout << "Primes: " << endl; for(int i = 1; i <= N; i++) { if(p[i]) { cout << i << " "; } } cout << endl; cout << "Euler Phi Function: " << endl; for(int i = 1; i <= N; i++) { cout << phi[i] << " "; } return 0; }
Solution
解决方案
欧拉函数:
#include <iostream> #include <math.h> #include <stdio.h> using namespace std; int phi(int x); int main() { int N; cin >> N; cout << phi(N) << endl; cout << endl; return 0; } int phi(int x) { int nRet = x; int nTmp = (int)sqrt(x); for(int i = 2; i <= nTmp; i++) { if(x % i == 0) { nRet = nRet / i * (i - 1); while(x % i == 0) { x /= i; } } } if(x > 1) { nRet = nRet / x * (x - 1); } return nRet; }
暴力:
#include <iostream> #include <math.h> #include <stdio.h> using namespace std; int gcd(int x, int y); int main() { int N, nRet = 0; cin >> N; for(int i = 1; i <= N; i++) { if(gcd(N, i) == 1) { nRet++; } } cout << nRet << endl; return 0; } int gcd(int x, int y) { if(y == 0) { return x; } return gcd(y, x % y); }
SGU不愧是经典题目的合集,每做一道题都会学到一些新的东西。