Luogu P2158仪仗队

欧拉函数

(1)~(n)中与(n)互质的数的个数被称为欧拉函数,记为(varphi(n))

[varphi(n)=n*frac{p_{1}-1}{p_{1}} * frac{p_{2}-1}{p_{2}} * ... * frac{p_{m}-1}{p_{m}}=n*prod_{质数p|n}^{} (1-frac{1}{p}) ]

根据欧拉函数的计算式,在分解质因数的时候求出欧拉函数即可:

int phi_(int n){
	int res=n;
	for(int i=2;i<=sqrt(n);i++){
		if(n%i==0){
			res=res/i*(i-1);
			while(n%i==0) n/=i;
		}
	}
	if(n>1) res=res/n*(n-1);
	return res;
}

题解

题目
自己推一下很容易发现,一个点((x,y))能被看到,当且仅当(gcd(x,y)=1)
又因为这是一个方阵,能看到的点关于((1,1))((n,n))的对角线是对称的,所以求出一半的点的数量(ans)(不包括((1,1))),(ans imes2+1)即为最终结果

  • 为什么加和的时候是(1)~((n-1))?
    因为点((1,1))是不包括的,三角形只有((n-1))
  • 为什么要特判(n==1)?
    因为只有一个点((1,1))的时候就是他看到的就是0个啊

code

纯欧拉函数

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#define maxn 40010
using namespace std;
template<typename T>
inline void read(T &x){
	x=0; bool flag=0; char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
	for(;isdigit(c);c=getchar()) x=x*10+(c^48);
	if(flag) x=-x;
}

int n;
int ans,phi[maxn];

int phi_(int n){
	int res=n;
	for(int i=2;i<=sqrt(n);i++){
		if(n%i==0){
			res=res/i*(i-1);
			while(n%i==0) n/=i;
		}
	}
	if(n>1) res=res/n*(n-1);
	return res;
}

int main(){
	read(n);
	if(n==1){cout<<0<<endl; return 0;}
	for(int i=1;i<=n;i++) phi[i]=phi_(i);
	for(int i=1;i<=n-1;i++) ans+=phi[i];
	cout<<2*ans+1<<endl;
	return 0;
}

Eratosthenes筛法

(O(n log n))

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#define maxn 40010
using namespace std;
template<typename T>
inline void read(T &x){
	x=0; bool flag=0; char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
	for(;isdigit(c);c=getchar()) x=x*10+(c^48);
	if(flag) x=-x;
}

int n;
int ans,phi[maxn];

void phi_(int n){
	for(int i=1;i<=n;i++) phi[i]=i;
	for(int i=2;i<=n;i++){
		if(phi[i]==i){
			for(int j=i;j<=n;j+=i){
				phi[j]=phi[j]/i*(i-1);
			}
		}
	}
}

int main(){
	read(n);
	if(n==1){cout<<0<<endl; return 0;}
	phi_(n);
	for(int i=1;i<=n-1;i++) ans+=phi[i];
	cout<<2*ans+1<<endl;
	return 0;
}
//Eratosthenes筛法,O(n log n)

线性筛

(O(n))

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#define maxn 40010
using namespace std;
template<typename T>
inline void read(T &x){
	x=0; bool flag=0; char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') flag=1;
	for(;isdigit(c);c=getchar()) x=x*10+(c^48);
	if(flag) x=-x;
}

int n;
int ans,cnt,mindiv[maxn],isprime[maxn],phi[maxn];

void phi_(int n){
	cnt=0;//质数数量 
	memset(mindiv,0,sizeof(mindiv));//最小质因子
	phi[1]=1;
	for(int i=2;i<=n;i++){
		if(mindiv[i]==0){//i是质数 
			mindiv[i]=i;
			isprime[++cnt]=i;
			phi[i]=i-1; 
		}
		for(int j=1;(j<=cnt)&&(i*isprime[j]<=n);j++){
			mindiv[i*isprime[j]]=isprime[j];
			phi[i*isprime[j]]=phi[i]*(i%isprime[j]?isprime[j]-1:isprime[j]);//"isprime[j]-1" and "phi[isprime[j]]" both right
			if(mindiv[i]==isprime[j]) break;
		}
	} 
	
}

int main(){
	read(n);
	if(n==1){cout<<0<<endl; return 0;}
	phi_(n);
	for(int i=1;i<=n-1;i++) ans+=phi[i];
	cout<<2*ans+1<<endl;
	return 0;
}
//线性筛,O(n) 
原文地址:https://www.cnblogs.com/DReamLion/p/14498370.html