UVA - 11426 GCD - Extreme (II)
传送门UVA - 11426
题意
给你
n
n
,让你求
题解
这道题就是个筛法的经典练习。
首先,设一个函数
f(x)
f
(
x
)
f(x)=∑i=1x−1∑j=i+1xgcd(i,j)
f
(
x
)
=
∑
i
=
1
x
−
1
∑
j
=
i
+
1
x
g
c
d
(
i
,
j
)
那么我们可以再设一个函数 g(x) g ( x )
g(x)=∑i=1x−1gcd(i,x)
g
(
x
)
=
∑
i
=
1
x
−
1
g
c
d
(
i
,
x
)
那么很显然
f(x)=f(x−1)+g(x)
f
(
x
)
=
f
(
x
−
1
)
+
g
(
x
)
那么我们就得到了一个递推式,这时我们就要想怎么得到所有的 g(x) g ( x )
那我们再设一个 h(n,x) h ( n , x )
h(n,x)=countni=1(gcd(n,i)=x)(ps:count是指求个数)
h
(
n
,
x
)
=
c
o
u
n
t
i
=
1
n
(
g
c
d
(
n
,
i
)
=
x
)
(
p
s
:
c
o
u
n
t
是
指
求
个
数
)
那么显然
g(x)=∑i=1n(h(x,i)×i)
g
(
x
)
=
∑
i
=
1
n
(
h
(
x
,
i
)
×
i
)
然后我们又知道
gcd(n,i)=x
g
c
d
(
n
,
i
)
=
x
⇒gcd(nx,ix)=1
⇒
g
c
d
(
n
x
,
i
x
)
=
1
那么
countni=1(gcd(nx,ix)=1)=phi(nx)(phi为欧拉函数)
c
o
u
n
t
i
=
1
n
(
g
c
d
(
n
x
,
i
x
)
=
1
)
=
p
h
i
(
n
x
)
(
p
h
i
为
欧
拉
函
数
)
那么我们就要预处理出来所有数字的欧拉函数,然后再用筛法求出所有的 g(x) g ( x ) ,然后再推出 f(x) f ( x )
首先数字挺大的了,先写一个 O(n) O ( n ) 的欧拉筛
ll phi[maxn];
bool notp[maxn];
ll prime[maxn], tot;
void getphi(int M) {
phi[1] = 1;
for (int i = 2; i <= M; i++) {
if (!notp[i]) {
prime[++tot] = i;
phi[i] = i - 1;
}
for (int j = 1; j <= tot && i * prime[j] <= M; j++) {
notp[i * prime[j]] = true;
if (i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j];
break;
} else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
实际上我们只要求出了欧拉函数就不用求 h(n,x) h ( n , x ) 了,直接筛出 g(x) g ( x ) 就行
for (int i = 1; i < maxn; ++i) {
for (int j = i * 2; j < maxn; j += i) {
g[j] += phi[j / i] * i;
}
}
剩下就没有难点了
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <queue>
#include <cstring>
#include <string>
#include <vector>
#include <stack>
#include <cmath>
#include <ctime>
#include <map>
#include <set>
#include <iomanip>
//#include <unordered_map>
#pragma comment(linker, "/STACK:102400000,102400000")
#define fir first
#define sec second
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
#define clr(x) memset(x,0,sizeof(x))
#define cld(x) memset(x,-1,sizeof(x))
#define clx(x) memset(x,63,sizeof(x))
#define cln(x) memset(x,-64,sizeof(x))
#define rush() int T;scanf("%d",&T);for(int NUM = 1; NUM <= T ; ++NUM)
#define pi 3.1415926
#define VM 100047
#define EM 400047
#define rd(x) scanf("%d",&x);
#define seed() srand((unsigned)time(NULL))
#define random(a, b) rand() % (b - a + 1) + a
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
const int inf = 0x3f3f3f3f;
const ll llf = 0x3f3f3f3f3f3f3f3f;
const int maxn = (int) 4e6 + 7;
const double eps = 1e-10;
const ll mod1 = (int) 1e9 + 7;
const ll mod2 = 998244353;
const ll has = 99959;
const int dx[] = {0, 1, 0, -1};
const int dy[] = {1, 0, -1, 0};
ll phi[maxn];
bool notp[maxn];
ll prime[maxn], tot;
void getphi(int M) {
phi[1] = 1;
for (int i = 2; i <= M; i++) {
if (!notp[i]) {
prime[++tot] = i;
phi[i] = i - 1;
}
for (int j = 1; j <= tot && i * prime[j] <= M; j++) {
notp[i * prime[j]] = true;
if (i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j];
break;
} else phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
ll g[maxn], f[maxn];
int main() {
std::ios::sync_with_stdio(false);
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
clr(notp);
getphi(maxn - 1);
ll n;
for (int i = 1; i < maxn; ++i) {
for (int j = i * 2; j < maxn; j += i) {
g[j] += phi[j / i] * i;
}
}
for (int i = 2; i < maxn; ++i) {
f[i] = f[i - 1] + g[i];
}
while (~scanf("%lld", &n) && n) {
printf("%lld\n",f[n]);
}
return 0;
}