欧拉函数例题(poj3090)
- 除了
(1,0)(1,1)(0,1)
三个点的,发现其余可视点gcd(x,y)=1
- 发现关于
(1,1)
这条线所有点都是对称的,不妨取下半部分,x<y
,此时1<=x<y<=n
,这就转化到求与y
互质数x
的个数, y
有多个选择,且y>=2
,最后答案从2~N
累加起来
求欧拉函数值,就是分解质因数的过程,
1.试除法分解质因数累加和,但是只能求出 $\upsilon(n)$,n
又要从2~n
遍历,
2. e氏筛O($n*loglogn$)
1 |
|
3.线性筛,标记合数的最小质因子的同时,根据欧拉函数的2个性质,求欧拉值
- $\upsilon(n)=(p-1)*\upsilon(n/p)$
( $p|n$ ~~~ $p^2!|n$ ) - $\upsilon(n) = p*\upsilon(n/p)$
($p|n$ ~~~$p^2|n$)题解:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30int tot = 0;//质数的个数
int prime[maxn];
int v[maxn];
int phi[maxn];
long long euler(int n) {
for (int i=2; i<=n; i++) {
if ( !v[i] ) {//v[i] == 0 不是合数,则是质数
v[i] = i;
prime[++tot] = i;
phi[i] = i-1;//单个质数的欧拉函数的值为n-1;
}
// 从i对应的合数开始累加质因子
for (int j=1; j<=tot; j++) {
//扫描不大于v[i]的每一个质数,来给合数标记最小质因子
if ( prime[j]>v[i] || prime[j]>n/i ) break;
v[i * prime[j]] = prime[j];
if ( i%prime[j] == 0 ) {
phi[i * prime[j]] = phi[i] * prime[j];//v(n) = v(n/p) * p;
}
else {
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
long long ans = 0;
for (int i=2; i<=n; i++) {
ans += phi[i];
}
return 2*ans+3;
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59#include <iostream>
using namespace std;
const int maxn=1e3+10;
int prime[maxn];
int v[maxn];
int phi[maxn];
/*long long euler(int n){
for (int i=2; i<=n; i++) prime[i] = i;
for (int i=2; i<=n; i++) {
if (prime[i]==i) {//值没有改变说明还是初始化的值,没有被它可能存在的约数筛掉
for (int j=i; j<=n; j+=i) {
prime[j] = prime[j] / i * (i - 1);
}
}
}
long long ans = 0;
for (int i=2; i<=n; i++) ans += prime[i];
return 2*ans+3;
}*/
//线性筛
int tot = 0;
long long euler(int n) {
for (int i=2; i<=n; i++) {
if ( !v[i] ) {
v[i] = i;
prime[++tot] = i;
phi[i] = i-1;//单个质数的欧拉函数的值为n-1;
}
// 从i对应的合数开始累加质因子
for (int j=1; j<=tot; j++) {
if ( prime[j]>v[i] || prime[j]>n/i ) break;
v[i * prime[j]] = prime[j];
if ( i%prime[j] == 0 ) {
phi[i * prime[j]] = phi[i] * prime[j];//v(n) = v(n/p) * p;
}
else {
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
long long ans = 0;
for (int i=2; i<=n; i++) {
ans += phi[i];
}
return 2*ans+3;
}
int main() {
freopen("a.txt","r",stdin);
int times;
scanf("%d",×);
int cnt = 0;
while (times--) {
int n;
scanf("%d",&n);
// e氏筛
printf("%d %d %lld\n",++cnt,n,euler(n));
}
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!