1. 程式人生 > >bzoj:[SDOI2008]儀仗隊

bzoj:[SDOI2008]儀仗隊

題目:https://www.luogu.org/problemnew/show/P2158

我們 考慮一下,對於每個點(x,y),設gcd(x,y) = d, 如果d != 1,則這個點一定會被(x/d,y/d)擋住,所以這題即求\sumφ(i)

φ有兩個性質

1、若p|n且q^2|n, 則\phi(n) = \phi(n/p)*p

2、若p|n但p^2p^2\nmid n,則\phi(n) =\phi(n/p) * (p - 1)

然後就有了我們可愛的線性篩

程式碼:

#include<bits/stdc++.h>
#define N 1000005
using namespace std;
int prime[N], vis[N], phi[N], sz, n, ans;
void get_phi(){
	for(int i = 2; i < N; i ++){
		if(!vis[i]){
			prime[++ sz] = i;
			phi[i] = i - 1;//顯而易見
		}
		for(int j = 1; prime[j] * i < N; j ++){
			vis[i * prime[j]] = 1;
			if(i % prime[j] == 0){
				phi[i * prime[j]] = phi[i] * prime[j]; //性質1
				break;
			}
			phi[i * prime[j]] = phi[i] * (prime[j] - 1);//性質2
		}
	}
}
int main(){
	get_phi();
	scanf("%d", &n);
	if(n == 1) {printf("0");return 0;}
	for(int i = 2; i < n; i ++) ans += phi[i];
	printf("%d", 3 + ans * 2);
	return 0;
}