数论函数练习记录(二)

数论函数练习记录(二)

参考资料:oi-wiki 杜教筛blogblog

[luoguP3768]简单的数学题

题目链接

于是问题转化为求出 $f(n)=n^2\varphi(n)$ 的前缀和,如此便可以数论分块了。

设 $g(n)=n^2$,那么 $(f*g)(n)=\sum\limits_{d\mid n}d^2\varphi(d)\frac{n^2}{d^2}=n^2\sum\limits_{d\mid n}\varphi(d)=n^3$,根据杜教筛理论,有:

即可计算。

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
#include<bits/stdc++.h>

using namespace std;

template<typename T>void read(T&x){x=0;int fl=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')
fl=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}x*=fl;}
template<typename T,typename...Args>inline void read(T&t,Args&...args){read(t);read(args...);}

typedef long long LL;
typedef vector<int> vi;
typedef pair<int, int> pii;
#define mp(x, y) make_pair(x, y)
#define pb(x) emplace_back(x)

const int N = 5000005;
LL p, inv2, inv6;

int phi[N], pList[N], pID;
bool notP[N];
void Euler(int n){
notP[0] = notP[1] = 1;
phi[1] = 1;
for(int i = 1; i <= n; i++){
if(notP[i] == 0){
pList[++pID] = i;
phi[i] = (i - 1) % p;
}
for(int j = 1; j <= pID; j++){
if(1ll * i * pList[j] > n) break;
notP[i * pList[j]] = 1;
if(i % pList[j] == 0){
phi[i * pList[j]] = 1ll * phi[i] * pList[j] % p;
break;
}
else phi[i * pList[j]] = 1ll * phi[i] * (pList[j] - 1) % p;
}
}
}

inline LL fpow(LL bs, LL idx, LL mod){
LL res = 1;
bs %= mod;
while(idx){
if(idx & 1) (res *= bs) %= mod;
(bs *= bs) %= mod;
idx >>= 1;
}
return res;
}

unordered_map<LL, LL> s;
LL pres[N];
LL apiadu(LL n){
if(n <= 5000000) return pres[n];
if(s.find(n) != s.end()) return s[n];
LL res = fpow(n%p*(n+1)%p*inv2%p, 2, p);
for(LL l = 2, r; l <= n; l = r + 1){
r = n / (n / l);
LL rs = r%p*(r+1)%p*(2*r%p+1)%p*inv6%p;
LL ls = (l-1)%p*l%p*(2*l%p-1)%p*inv6%p;
res -= (rs - ls) * apiadu(n / l) % p;
((res %= p) += p) %= p;
}
return s[n] = res;
}

LL n;
inline LL solve(){
LL res = 0;
for(LL l = 1, r; l <= n; l = r + 1){
r = n / (n / l);
res += fpow((n/l)%p*(n/l+1)%p, 2, p) * (apiadu(r) - apiadu(l-1)) % p;
((res %= p) += p) %= p;
}
return res * fpow(4, p-2, p) % p;
}

int main(){
read(p, n);
inv2 = fpow(2, p-2, p), inv6 = fpow(6, p-2, p);
Euler(5000000);
for(int i = 1; i <= 5000000; i++)
pres[i] = (pres[i-1] + 1ll * i * i % p * phi[i] % p) % p;
printf("%lld\n", solve());
return 0;
}

[51nod 1220]约数之和

题目链接

注意到:

所以,

杜教筛筛出 $d\mu(d)$ 的前缀和以及 $\sigma(i)$ 的前缀和之后,就可以数论分块了。

$d\mu(d)$ 前缀和:设 $f(n)=n\mu(n),\;g(n)=\text{id}(n)$,则 $(fg)(n)=\sum\limits_{d=1}^nd\mu(d)\frac{n}{d}=n\cdot(\mu1)(n)=n\cdot\epsilon(n)=\epsilon(n)$,根据杜教筛理论,有:

$\sigma(i)$ 前缀和:设 $f(n)=\sigma(n)\;,g(n)=\mu(n)$,则 $(f*g)(n)=\text{id}(n)$,根据杜教筛理论,有:

所以筛出莫比乌斯函数的前缀和就可以了。

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
#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 1000005;
const LL MOD = 1e9+7;

inline LL fpow(LL bs, LL idx){
LL res = 1;
bs %= MOD;
while(idx){
if(idx & 1) (res *= bs) %= MOD;
(bs *= bs) %= MOD;
idx >>= 1;
}
return res;
}

int mu[N], sigma[N], g[N], pList[N], pID;
bool notP[N];
void Euler(int n){
notP[0] = notP[1] = 1;
mu[1] = 1, sigma[1] = 1, g[1] = 1;
for(int i = 1; i <= n; i++){
if(notP[i] == 0){
pList[++pID] = i;
mu[i] = -1, sigma[i] = 1 + i, g[i] = 1 + i;
}
for(int j = 1; j <= pID; j++){
if(1ll * i * pList[j] > n) break;
notP[i * pList[j]] = 1;
if(i % pList[j] == 0){
mu[i * pList[j]] = 0;
sigma[i * pList[j]] = sigma[i] / g[i] * (g[i] * pList[j] + 1);
g[i * pList[j]] = (g[i] * pList[j] + 1);
break;
}
else{
mu[i * pList[j]] = -mu[i];
sigma[i * pList[j]] = sigma[i] * (1 + pList[j]);
g[i * pList[j]] = 1 + pList[j];
}
}
}
}

unordered_map<LL, LL> muS, sigmaS, fS;
LL pre_muS[N], pre_sigmaS[N], pre_fS[N];
LL apiadu_mu(LL n){
if(n <= 1000000) return pre_muS[n];
if(muS.find(n) != muS.end()) return muS[n];
LL res = 1;
for(LL l = 2, r; l <= n; l = r + 1){
r = n / (n / l);
res -= apiadu_mu(n / l) * (r - l + 1) % MOD;
((res %= MOD) += MOD) %= MOD;
}
return muS[n] = res;
}
LL apiadu_sigma(LL n){
if(n <= 1000000) return pre_sigmaS[n];
if(sigmaS.find(n) != sigmaS.end()) return sigmaS[n];
LL res = n * (n + 1) / 2 % MOD;
for(LL l = 2, r; l <= n; l = r + 1){
r = n / (n / l);
res -= (apiadu_mu(r) - apiadu_mu(l-1)) * apiadu_sigma(n / l) % MOD;
((res %= MOD) += MOD) %= MOD;
}
return sigmaS[n] = res;
}
LL apiadu_f(LL n){
if(n <= 1000000) return pre_fS[n];
if(fS.find(n) != fS.end()) return fS[n];
LL res = 1;
for(LL l = 2, r; l <= n; l = r + 1){
r = n / (n / l);
res -= (l + r) * (r - l + 1) / 2 % MOD * apiadu_f(n / l) % MOD;
((res %= MOD) += MOD) %= MOD;
}
return fS[n] = res;
}

int main(){
Euler(1000000);
for(int i = 1; i <= 1000000; i++){
pre_muS[i] = pre_muS[i-1] + mu[i];
pre_sigmaS[i] = (pre_sigmaS[i-1] + sigma[i]) % MOD;
pre_fS[i] = ((pre_fS[i-1] + i * mu[i]) % MOD + MOD) % MOD;
}
int n; scanf("%d", &n);
LL res = 0;
for(LL l = 1, r; l <= n; l = r + 1){
r = n / (n / l);
res += (apiadu_f(r) - apiadu_f(l-1) + MOD) % MOD * apiadu_sigma(n / l) % MOD * apiadu_sigma(n / l) % MOD;
((res %= MOD) += MOD) %= MOD;
}
printf("%lld\n", res);
return 0;
}

[hdu6706] huntian oy

题目链接

设 $f(n)=n\varphi(n)$,$g(n)=n$,则 $(f*g)(n)=\sum\limits_{d\mid n}d\varphi(d)\frac{n}{d}=n\sum\limits_{d\mid n}\varphi(d)=n^2$,根据杜教筛理论:

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
#include<bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 1000005;
const LL MOD = 1e9+7;
const LL inv2 = 500000004;
const LL inv3 = 333333336;
const LL inv6 = 166666668;

int phi[N], pList[N], pID;
bool notP[N];
void Euler(int n){
notP[0] = notP[1] = 1;
phi[1] = 1;
for(int i = 1; i <= n; i++){
if(notP[i] == 0){
pList[++pID] = i;
phi[i] = i - 1;
}
for(int j = 1; j <= pID; j++){
if(1ll * i * pList[j] > n) break;
notP[i * pList[j]] = 1;
if(i % pList[j] == 0){
phi[i * pList[j]] = phi[i] * pList[j];
break;
}
else phi[i * pList[j]] = phi[i] * (pList[j] - 1);
}
}
}

unordered_map<LL, LL> fS;
LL preS[N];
LL apiadu_f(LL n){
if(n <= 1000000) return preS[n];
if(fS.find(n) != fS.end()) return fS[n];
LL res = n % MOD * (n + 1) % MOD * (2 * n % MOD + 1) % MOD * inv6 % MOD;
for(LL l = 2, r; l <= n; l = r + 1){
r = n / (n / l);
res -= (l + r) % MOD * (r - l + 1) % MOD * inv2 % MOD * apiadu_f(n / l) % MOD;
((res %= MOD) += MOD) %= MOD;
}
return fS[n] = res;
}

int main(){
Euler(1000000);
for(int i = 1; i <= 1000000; i++)
preS[i] = (preS[i-1] + 1ll * phi[i] * i % MOD) % MOD;
int T; for(scanf("%d", &T); T; T--){
LL n, res;
scanf("%lld%*d%*d", &n);
res = (apiadu_f(n) - 1) % MOD * inv2 % MOD;
((res %= MOD) += MOD) %= MOD;
printf("%lld\n", res);
}
return 0;
}
作者

xyfJASON

发布于

2020-09-21

更新于

2021-02-25

许可协议

评论