【题解】[SDOI2012] Longge 的问题
题目信息
题目来源:CCF 山东省选 2012;
在线评测地址:Luogu#2303;
运行限制:时间不超过 \(3.00\ \textrm{s}\),空间不超过 \(128\ \textrm{MiB}\)。
题目背景
Longge 的数学成绩非常好,并且他非常乐于挑战高难度的数学问题。
题目描述
现在问题来了:给定一个整数 \(n\),你需要求出 \(\sum\limits_{i=1}^n \gcd(i,n)\),其中 \(\gcd(i,n)\) 表示 \(i\) 和 \(n\) 的最大公因数。
输入格式
输入只有一行一个整数,表示 \(n\)。
输出格式
输出一行一个整数表示答案。
数据规模与约定
- 对于 \(60\%\) 的数据,保证 \(n\le 2^{16}\)。
- 对于 \(100\%\) 的数据,保证 \(1\le n\le 2^{32}\)。
分析
这道题太经典了,以至于后面的很多数论题都是模仿这个形式的。
\(60\ \texttt{pts}\)
暴力求即可,复杂度 \(\mathcal{O}(n\log n)\)。
\(100\ \texttt{pts}\)
我们要推一下式子,来优化这个算法。
枚举所有因数,计算即可,复杂度 \(\mathcal{O}(\sigma(n)\sqrt{n})\),可以 AC。
Bonus
当然,这道题这么数学,其实有更好的做法,可以做到 \(\mathcal{O}(\sqrt{n})\) 的优秀复杂度。
具体内容可以看这一篇文章。
注意事项
这道题非常细节,很容易不知不觉就 WA、TLE。
边界问题
看到那个数据范围 \(\le 2^{32}\) 没有?\(n\) 是可以等于 \(2^{32}\) 的,所以别忘了开 long long
。
当然所有中间变量都得开 long long
,否则会出现溢出。
同时,判定质数时注意平方数情况。
特判问题
求 \(\varphi(n)\) 时,得先判质数,然后进行质因数分解。
同时,质因数分解时循环也只能开到 \(\sqrt{n}\) 级别,最后还要特判是否有没有除掉的数。否则一个 \(2\times (2^{31}-1)\) 就能卡得飞起。
还有,你有没有把 \(1\) 判为质数呢?特判一定要加!
Code
经过了好几次提交以后,这道题终于 \(\color{GreenYellow}{\texttt{AC}}\) 了。
#include <cstdio>
using namespace std;
typedef long long ll;
ll phi(ll x) // 计算
{
ll ans = 1;
bool flag = false;
for (ll i = 2; i * i <= x; i++) // 判质数
if (!(x % i))
{
flag = true;
break;
}
if (!flag && x != 1) // 是质数
return x - 1; // 退出
for (ll i = 2; i * i <= x; i++) // 否则就开始找质因数
if (!(x % i)) // 找到了
{
ans *= (i - 1), x /= i; // 计算贡献
while (!(x % i))
x /= i, ans *= i;
}
if (x != 1) // 还没算干净,一定是质数
ans *= x - 1; // 直接计算贡献
return ans; // 返回答案
}
int main()
{
ll n, ans = 0;
scanf("%lld", &n); // 输入
for (ll i = 1; i * i <= n; i++) // 筛因数
if (!(n % i)) // 找到了(一对)
{
ans += phi(i) * (n / i); // 计算一个
if (i * i < n) // 不是平方数
ans += phi(n / i) * i; // 就再计算一个。
}
printf("%lld\n", ans); // 输出
return 0; // 然后就 AC 了、
}
本文来自博客园,作者 5ab,转载请注明链接哦 qwq
博客迁移啦,来看看新博客吧 -> https://5ab-juruo.oier.space/