pku 2480 Longge's problem 最大公约数的和

做法:
直接求过不了
只能考虑  对于gcd(M,N)=i 有Ci个M满足此式 答案便是∑(Ci*i)
gcd(M,N)=i  <=> gcd(M/i,N/i)=1
而求gcd(M/i,N/i)=1 有多少个M/i满足 这便是欧拉函数Phi()的定义
所以就转化为了求Phi(N/i)

枚举每个 M|N  求出Phi(N/i)  答案便是 ∑(Phi(N/i)*i)
那么如何枚举每个  M|N 呢?
很简单 枚举1到sqrt(N)的所有整数,所有的约数便是 j|N (N/j)|N
这样就搞定了
#include<stdio.h>
#include<math.h>
#include<string.h>
#include<iostream>
using namespace std;
typedef long long LL;
const int nmax = 50005;
int prime[nmax], flag[nmax];
int plen;
void mkprime() {
int i, j;
memset(flag, -1, sizeof(flag));
for (i = 2; i < nmax; i++) {
if (flag[i]) {
for (j = i + i; j < nmax; j += i)
flag[j] = 0;
}
}
for (i = 2, plen = 0; i < nmax; i++)
if (flag[i])
prime[plen++] = i;
}
int getPhi(int n) {
int i, te, phi;
te = (int) sqrt(n * 1.0);
for (i = 0, phi = n; (i < plen) && (prime[i] <= te); i++) {
if (n % prime[i] == 0) {
phi = phi / prime[i] * (prime[i] - 1);
while (n % prime[i] == 0) {
n /= prime[i];
}
}
}
if (n > 1) {
phi = phi / n * (n - 1);
}
return phi;
}

void solve(int n) {
int i, j, te;
LL sum;
te = static_cast<int>(sqrt(1.0 * n));
for (i = 1, sum = 0; i <= te; i++) {
if (n % i == 0) {
j = n / i;
sum += i * getPhi(j);
if (i != j) {
sum += j * getPhi(i);
}
}
}
printf("%I64d\n", sum);
}
int main() {
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int n;
mkprime();
while (~scanf("%d", &n)) {
solve(n);
}
return 0;
}

 
 
[分析]:

设f(n)=∑gcd(i,n)

推论1:1~n与n的最大公约数为p的个数等于φ(n div p)

所以可以得出f(n)=∑φ(n div p)*p (p|n)    

设 n=(p1^k1)(p2^k2)....(pn^kn)   (p1,p2..pn ∈ Prime)

所以有: f(n)=f(p1^k1)f(p2^k2)....f(pn^kn)

所以我们只需求出求f(pi^ki)即可

f(p^k)=∑[( p^c )φ( p^(k-c) )] (0<=c<=k)   由于∑k比较小,我们可以枚举c

对于φ( p^i)(p ∈ Prime)有 φ( p^i)=(p-1)p^(i-1) 但有φ(1)=1

 

#include<stdio.h>
#include<string.h>
#include<math.h>
#define LL long long
#define nmax 46345
int prime[nmax], plen;
void mkprime() {
int i, j;
memset(prime, -1, sizeof(prime));
for (i = 2; i < nmax; i++) {
if (prime[i]) {
for (j = i + i; j < nmax; j += i) {
prime[j] = 0;
}
}
}
for (i = 2, plen = 0; i < nmax; i++) {
if (prime[i]) {
prime[plen++] = i;
}
}
}
int getPow(int a, int b) {
int res;
res = 1;
while (b) {
if (b & 1) {
res = res * a;
}
b >>= 1;
a = a * a;
}
return res;
}
int getpPhi(int p, int c) {
if (c == 0) {
return 1;
}
return (p - 1) * getPow(p, c - 1);
}
LL cal(int p, int c) {
int i;
LL sum, temp;
for (i = 0, sum = 0, temp = 1; i <= c; i++) {
sum += temp * getpPhi(p, c - i);
temp *= p;
}
return sum;
}
void solve(int n) {
int i, te, cnt;
LL res;
te = (int) (sqrt(n * 1.0));
for (i = 0, res = 1; (i < plen) && (prime[i] <= te); i++) {
if (n % prime[i] == 0) {
cnt = 0;
while (n % prime[i] == 0) {
cnt++;
n /= prime[i];
}
res = res * cal(prime[i], cnt);
}
}
if (n > 1) {
res = res * cal(n, 1);
}
printf("%I64d\n", res);

}

int main() {
#ifndef ONLINE_JUDGE
freopen("data.in", "r", stdin);
#endif
int n;
mkprime();
while (scanf("%d", &n) != EOF) {
solve(n);
}
return 0;
}


原文地址:https://www.cnblogs.com/xiaoxian1369/p/2119499.html