fsy's blog

燃峥嵘岁月,烈日终破云。

SPOJ 11202 Number Theory

题目传送门

给定两个函数:

设 $n$ 的唯一分解式为 $p_1^{e_1}p_2^{e_2}…p_m^{e_m}$
$$f(n) = \prod_{i=1}^{m} p_i^{2e_i + 1}+1$$
$$g(n) = \sum_{i=1}^{n} \frac{n}{\gcd(i,n)}$$
求 $\frac{f(n)}{g(n)} \mod 10^{12}$。

题解

首先直接除是不可做的,我们要把 $g$ 函数转化一下。

考虑枚举 $g$ 函数中的 $d = \gcd(i, n) (1 \le d \le n)$。由欧拉函数的定义和性质可知,满足 $\gcd(i, n) = d$ 的 $i$ 只有 $\varphi(d)$ 个。所以 $g(n) = \sum_{d|n} \frac{n}{d} \times \varphi(\frac{n}{d})$,进一步思考,我们可以得出:$g(n) = \sum_{d|n} {d} \times \varphi({d})$

定理1 $g(n)$ 是积性函数。
证明:设两个函数 $g_1(n) = n$ 和 $g_2(n) = \varphi(n)$。由于 $g_1$ 与 $g_2$ 均为积性函数。则 $g = \sum_{d|n} g_1 g_2$ 自然也是积性函数。

设 $n$ 的唯一分解式为 $p_1^{e_1}p_2^{e_2}…p_m^{e_m}$。则 $g(n) = g(p_1^{e_1}) \times g(p_2^{e^2}) \times \cdots \times g(p_m^{e_m})$。

由 phi 函数的性质可知:$\varphi(p^{e}) = (p - 1) \times p^{e-1}$,进一步得到:$\varphi(p^e) = p^e - p^{e-1}$

所以,$g(p^{e}) = \sum_{d|p^e} d \times \varphi(d) = \sum_{i = 0}^{e} p^i \times \varphi(p^i) $。

当 $i = 0$ 时,$g(p^i)$ 明显等于 $1$。

所以原式又可以化为 $= 1 + \sum_{i=1}^{e} p^i \times (p^i - p^{i - 1}) = 1 + \sum_{i = 1}^{e} p^{2i} - p^{2i-1}$。

化简,得 $g(p^{e}) = 1 - p + p^2 - p^3 + p^4 - p^5+ p^6 - \cdots - p^{2e-1} + p^{2e}$。

对其进行分组,得:$g(p^e) = 1 + (p-1) (p + p^3 + p^5 + p^7 + p^9 + \cdots + p^{2e-1})$

两式同乘 $p + 1$,得:$(p+1)g(p^e) = p + 1 + (p^2 - 1)(p + p^3 + p^5 + \cdots + p^{2e-1})$

所以:$(p + 1)g(p^e) = p + 1 + p^3 - p + p^5 - p^3 + p^7 - p^5 + \cdots + p^{2e+1} - p^{2e-1} = p^{2e+1} + 1$。

即 $g(p^e) = \frac{p^{2e+1}+1}{p + 1}$。

回到原式, $g(n) = g(p_1^{e_1}) \times g(p_2^{e^2}) \times \cdots \times g(p_m^{e_m}) = \prod_{i=1}^{m} \frac{p_i^{2e_i+1}+1}{p_i+1}$

所以,$\frac{f(n)}{g(n)} = \prod_{i-1}^{m} p_i + 1$。

所以只需把 $n$ 分解质因数即可。

使用 Pollard-rho 算法,预计时间复杂度 $O(T \times n^{\frac{1}{4}})$。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include <bits/stdc++.h>
#pragma GCC optimize("Ofast")
#define LL long long
#define _rep(i, x, y) for (int i = x; i <= y; i++)

const int prime_list[12] = { 2, 3, 5, 7, 11, 13, (LL) 1e9 + 7 };
const int small_prime[6] = { 2, 3, 5, 7, 11 };
const int luck_prime = 19260817;
const LL mod = 1000000007;

template <typename T>
inline void read(T &x) {
x = 0;
LL f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) {
if (c == '-')
f = -f;
}
for (; isdigit(c); c = getchar()) {
x = x * 10 + c - 48;
}
x *= f;
}

LL ksc(LL a, LL b, LL m) {
LL d = ((long double)a / m * b + 1e-8);
LL r = a * b - d * m;
return r < 0 ? r + m : r;
}

LL ksm(LL a, LL b, LL p) {
LL sum = 1;
for (; b >= 1; b >>= 1, a = ksc(a, a, p)) {
if (b & 1)
sum = ksc(sum, a, p);
}
return sum;
}

LL gcd(LL a, LL b) {
if (!a) return b;
if (!b) return a;
#define ctz __builtin_ctzll
int t = ctz(a | b);
a >>= ctz(a);
do {
b >>= ctz(b);
if (a > b) {
LL t = b;
b = a;
a = t;
}
b -= a;
} while (b != 0);
return a << t;
}

bool miller_rabin(LL x) {
if (x < 2)
return false;
if (x == 2 || x == 3 || x == 5 || x == 7)
return true;
if (x % 2 == 0 || x % 3 == 0 || x % 5 == 0 || x % 7 == 0)
return false;
LL cnt = 0, rem = x - 1;
while (!(rem & 1)) {
cnt++;
rem >>= 1;
}

_rep(i, 0, 6) {
if(x == prime_list[i]) return true;
if(x % prime_list[i] == 0) return false;
LL rt = ksm(prime_list[i], rem, x);
LL y = rt;
_rep(i, 1, cnt) {
rt = ksc(rt, rt, x);
if (rt == 1 && y != 1 && y != x - 1) {
return false;
}
y = rt;
}
if (rt != 1)
return false;
}
return true;
}

int M = (1 << 7) - 1;
LL f(LL x, LL p, LL c) {
LL ans = ksc(x, x, p) + c;
return ans < p ? ans : ans - p;
}
LL abs(LL x) {
return x < 0? -x : x;
}
LL pollards_rho(LL x) {
if (x % 2 == 0)
return 2;
if (x % 3 == 0)
return 3;
if (x % 5 == 0)
return 5;
if (x % 7 == 0)
return 7;
LL base = 1ll * rand() % (x - 1) + 1;
LL sp = 0, tp = 0;
int i = 1, j = 0;
LL val = 1;
LL d;
for(i = 1; ; i <<= 1, sp = tp, val = 1) {
for(j = 1; j <= i; ++j) {
tp = f(tp, x, base);
val = ksc(val, abs(tp - sp) , x);
if(!(j & M)) {
d = gcd(val, x);
if(d > 1) return d;
}
}
d = gcd(val, x);
if(d > 1) return d;
}
}

LL factor[510], m = 0;
void work(LL x) {
if(x <= 1) return;
if(miller_rabin(x)) {
factor[++m] = x;
return;
}
LL num = x;
while(num >= x) {
num = pollards_rho(x);
}
while(x % num == 0) {x /= num;}
if(x >= 2) work(x);
if(num >= 2) work(num);
}

int main() {
srand((unsigned)time(0));
int T;
read(T);

while(T--) {
m = 0;
LL N; read(N);
work(N);
std::sort(factor + 1, factor + m + 1);
int len = std::unique(factor + 1, factor + m + 1) - (factor + 1);
LL ans = 1;
_rep(i, 1, len) {
ans = (ans * (factor[i] + 1) % mod) % mod;
}
printf("%lld\n", ans);
}

return 0;
}