Longge's problem
Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9220 Accepted: 3085 Description
Longge is good at mathematics and he likes to think about hard mathematical problems which will be solved by some graceful algorithms. Now a problem comes: Given an integer N(1 < N < 2^31),you are to calculate ∑gcd(i, N) 1<=i <=N.
"Oh, I know, I know!" Longge shouts! But do you know? Please solve it.Input
Input contain several test case.
A number N per line.Output
For each N, output ,∑gcd(i, N) 1<=i <=N, a line
Sample Input
2 6Sample Output
3 15Source
POJ Contest,Author:Mathematica@ZSU
【思路】
要求。设某个i与N的最大公约数为p,则有N = p × m,i = p × n,且n <= m,n与m互质。显然与N的最大公约数为p的i的个数就是n的个数,也就是。所以枚举N的所有因数搞一搞就是答案了。我们把N分解一下,它的质因数不会太多,然后组合出N的所有因数就好了(我将分解后的结果放在map里,暴力组合时为此还开发出迭代器作为递归函数参数的新写法,后来看别人的题解发现这种做法其实很智障,没必要分解,只需要将1到遍历一下考察数对就能得到所有因数了,读者看我的代码就当看新奇好了)。
【代码】
//******************************************************************************
// File Name: POJ_2480.cpp
// Author: Shili_Xu
// E-Mail: shili_xu@qq.com
// Created Time: 2018年07月29日 星期日 09时26分22秒
//******************************************************************************
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
int n;
ll ans;
map<int, int> p;
int phi(int x)
{
int ans = x;
for (int i = 2; (ll)i * i <= x; i++) {
if (x % i == 0) {
ans /= i, ans *= (i - 1);
while (x % i == 0) x /= i;
}
}
if (x > 1) ans /= x, ans *= (x - 1);
return ans;
}
void get_factor(int x)
{
p.clear();
for (int i = 2; (ll)i * i <= x; i++) {
while (x % i == 0) x /= i, (!p.count(i) ? p[i] = 1 : p[i]++);
}
if (x > 1) p[x]++;
}
void dfs(map<int, int>::iterator it, int now)
{
if (it == p.end()) {
int m = n / now;
ans += (ll)phi(m) * now;
return;
}
map<int, int>::iterator a = it;
for (int i = 0; i <= it->second; i++) dfs(++it, now), it = a, now *= it->first;
}
int main()
{
while (scanf("%d", &n) == 1) {
get_factor(n);
ans = 0;
dfs(p.begin(), 1);
printf("%lld\n", ans);
}
return 0;
}