【题目来源】
https://www.luogu.com.cn/problem/P2303
【题目描述】
给定一个整数 n,你需要求出 ∑ gcd(i,n),i=1~n。其中 gcd(i,n) 表示 i 和 n 的最大公因数。
【输入格式】
输入只有一行一个整数,表示 n。
【输出格式】
输出一行一个整数表示答案。
【输入样例】
6
【输出样例】
15
【数据规模与约定】
对于 60% 的数据,保证 n≤2^16。
对于 100% 的数据,保证 1≤n<2^32。
【算法分析】
欧拉函数 φ(n) 是数论中的重要函数,用于计算 1~n 中与 n 互质的正整数的个数。特别地,当 n=1 时,φ(1)=1。质因数分解是欧拉函数计算的核心步骤。计算结果可能超出 int 范围,对大数需使用 long long。C++实现欧拉函数的两种经典方法如下所示。
(1)质因数分解法
cpp
#include <bits/stdc++.h>
using namespace std;
int oula_phi(int x) {
int ans=x;
for(int i=2; i*i<=x; i++) {
if(x%i==0) {
ans=ans/i*(i-1);
while(x%i==0) x/=i;
}
}
if(x>1) ans=ans/x*(x-1);
return ans;
}
int main() {
int x;
cin>>x;
cout<<oula_phi(x);
return 0;
}
/*
in:10
out:4
*/
(2)优化版筛法
cpp
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int phi[maxn];
void oula_sieve_opt() {
phi[1]=1;
for(int i=2; i<maxn; i++) {
if(!phi[i]) {
for(int j=i; j<maxn; j+=i) {
if(!phi[j]) phi[j]=j;
phi[j]=phi[j]/i*(i-1);
}
}
}
}
int main() {
int x;
cin>>x;
oula_sieve_opt();
cout<<phi[x];
return 0;
}
/*
in:10
out:4
*/
【算法代码一:long long】
代码中 #define int long long 是 C/C++ 中的预处理宏定义指令,其核心作用是将代码中所有的 int 类型标识符替换为 long long 类型。注意千万不要写成 #define long long int 。
++使用++++#define int long long 将 int 替换为 long long 后,需配合 signed main(){ }++ ++使用++,以避免使用 int main(){ } 时导致返回值类型错误。
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
int oula_phi(int x) {
int ans=x;
for(int i=2; i*i<=x; i++) {
if(x%i==0) {
ans=ans/i*(i-1);
while(x%i==0) x/=i;
}
}
if(x>1) ans=ans/x*(x-1);
return ans;
}
signed main() {
int n,cnt=0;
scanf("%lld",&n); //cin>>n;
for(int i=1; i*i<=n; i++) {
if(n%i==0) {
cnt+=i*oula_phi(n/i);
if(i!=n/i) cnt+=(n/i)*oula_phi(i);
}
}
printf("%lld",cnt); //cout<<cnt<<endl;
return 0;
}
/*
in:6
out:15
*/
【算法代码二:__int128】
在提高+、省选及NOI赛题中,经常会遇到超级大的输入输出,此时若++使用 C/C++ 中的宏指令++++#define int __int128 将代码中所有的 int 类型替换为 __int128 类型,需配合 signed main(){ }++ ++使用++ ,否则将会导致使用 int main(){ } 时的返回值类型错误。
但是,__int128 类型无标准 I/O 支持,无法直接使用 cin / cout / scanf / printf,需手动实现读写函数。
cpp
#include <bits/stdc++.h>
#define int __int128
using namespace std;
int oula_phi(int x) {
int ans=x;
for(int i=2; i*i<=x; i++) {
if(x%i==0) {
ans=ans/i*(i-1);
while(x%i==0) x/=i;
}
}
if(x>1) ans=ans/x*(x-1);
return ans;
}
int read() { //fast read
int x=0,f=1;
char c=getchar();
while(c<'0' || c>'9') { //!isdigit(c)
if(c=='-') f=-1;
c=getchar();
}
while(c>='0' && c<='9') { //isdigit(c)
x=x*10+c-'0';
c=getchar();
}
return x*f;
}
void print(int x) {
if(x<0) putchar('-'), x=-x;
if(x>9) print(x/10);
putchar(x%10+'0');
}
signed main() {
int n,cnt=0;
n=read();
for(int i=1; i*i<=n; i++) {
if(n%i==0) {
cnt+=i*oula_phi(n/i);
if(i!=n/i) cnt+=(n/i)*oula_phi(i);
}
}
print(cnt);
return 0;
}
/*
in:6
out:15
*/
【参考文献】
https://www.luogu.com.cn/problem/P5091
https://www.luogu.com.cn/problem/P2568
https://www.luogu.com.cn/problem/P2303