Skip to content

Commit 0b7be51

Browse files
committed
update
1 parent b275476 commit 0b7be51

7 files changed

Lines changed: 791 additions & 0 deletions

File tree

_posts/2025-02-05-1.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3082,6 +3082,23 @@ $$
30823082
30833083
* 除数函数:$\sigma_k(n)=\sum\limits_{d\mid n}d^k$,$\sigma_0(n)$ 通常记作 $d(n)$ 或 $\tau(n)$,$\sigma_1(n)$ 通常记作 $\sigma(n)$。(`\sigma`)
30843084
3085+
<details class="note">
3086+
<summary>$d(n)$ 的求法</summary>
3087+
<p>
3088+
令 $n=p_1^{c_1}p_2^{c_2}\cdots p_k^{c_k}$,其中 $p_1,p_2,\cdots,p_k$ 均为质数。
3089+
</p>
3090+
<p>
3091+
对于每一个指数 $c_i$ 的更改,都会产生新的因数。每一个 $i$,都有 $c_i+1$ 种选择。显然有:
3092+
</p>
3093+
$$
3094+
d(n)=\prod_{i=1}^k(c_i+1)
3095+
$$
3096+
</p>
3097+
<p>
3098+
时间复杂度 $\mathcal O\left(\sqrt n\right)$。
3099+
</p>
3100+
</details>
3101+
30853102
* 欧拉函数:$\varphi(n)$。(`\varphi`)
30863103
30873104
* 莫比乌斯函数:
@@ -3097,6 +3114,24 @@ $$
30973114
30983115
$\mu(n)=0$ 即 $n$ 含有平方因子。(`\mu`)
30993116
3117+
同时,除数函数 $d(n)$ 即 $n$ 的因数个数,且 $d(ij)$ 满足:
3118+
3119+
$$
3120+
\begin{aligned}
3121+
d(ij)&=\sum_{x\mid i}\sum_{y\mid j}[x\perp y]
3122+
\end{aligned}
3123+
$$
3124+
3125+
<details class="note">
3126+
<summary>证明</summary>
3127+
<p>
3128+
令 $i=p_1^{c_1}p_2^{c_2}\cdots p_k^{c_k},j={p'_1}^{c'_1}{p'_2}^{c'_2}\cdots {p'_{k'}}^{c'_{k'}}$。如果将指数对位相加,则可以得到 $ij$ 的质因数分解形式。
3129+
</p>
3130+
<p>
3131+
将每一个质因子 $p_l$ 枚举 $c_l+c'_l+1$ 次,便可以得到全部的因数。因此枚举 $x\mid i,y\mid j$,但是需要保证 $x,y$ 不包含重复质因子,即 $x\perp y$。
3132+
</p>
3133+
</details>
3134+
31003135
## 迪利克雷卷积
31013136
31023137
对于数论函数 $f,g$,记 $h=f*g$ 为 $f,g$ 通过迪利克雷卷积相乘的到的结果,即:

_posts/2025-8-18-1.md

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
---
2+
layout: post
3+
title: "题解:[HEOI2016/TJOI2016] 排序"
4+
subtitle: "洛谷P2824 | ODT 维护。"
5+
date: 2025-8-18
6+
author: "TH911"
7+
header-img: "img/2024/10/006.jpeg"
8+
header-mask: 0.4
9+
tags:
10+
- 题解
11+
- 提高+/省选−
12+
- ODT 珂朵莉树
13+
- 线段树
14+
words:
15+
---
16+
17+
> [题目传送门](https://www.luogu.com.cn/problem/P2824)
18+
19+
# 问题转化
20+
21+
发现询问有且仅有一次,且仅询问**一个位置**
22+
23+
因此无需得出整个序列,得出排序后的 $a_q$ 即可。区间排序实在不好做,因此考虑能否找到一种方式转化。
24+
25+
答案与 $a_q$ 正相关,其余其实并不重要。因此不妨有:
26+
27+
$$
28+
a_i\leftarrow
29+
\begin{cases}
30+
1&a_i\geq a_q\\
31+
0&a_i<a_q
32+
\end{cases}
33+
$$
34+
35+
这样,排序即可视为区间赋值。
36+
37+
枚举答案 $a_q=x$,可以 $\mathcal O(m\log n)$ 维护区间赋值,若最后 $a_q=1$,则说明 $x$ 是可能的解,且真实的 $a_q\geq x$。
38+
39+
因此可以二分。
40+
41+
时间复杂度 $\mathcal O(m\log^2n)$。
42+
43+
# AC 代码
44+
45+
只有一次查询,因此使用 ODT 实现。时间复杂度同线段树。
46+
47+
```cpp
48+
//#include<bits/stdc++.h>
49+
#include<algorithm>
50+
#include<iostream>
51+
#include<cstring>
52+
#include<iomanip>
53+
#include<cstdio>
54+
#include<string>
55+
#include<vector>
56+
#include<cmath>
57+
#include<ctime>
58+
#include<deque>
59+
#include<queue>
60+
#include<stack>
61+
#include<list>
62+
#include<set>
63+
using namespace std;
64+
constexpr const int N=1e5,M=1e5;
65+
int n,m,q,backup[N+1],a[N+1];
66+
struct operation{
67+
int op,l,r;
68+
}op[M+1];
69+
struct ODT{
70+
struct node{
71+
int l,r;
72+
mutable int value;
73+
};
74+
friend bool operator <(node a,node b){
75+
return a.l<b.l;
76+
}
77+
set<node>t;
78+
void build(int l,int r){
79+
t.insert({l,r+1});
80+
}
81+
void clear(){
82+
t.clear();
83+
}
84+
auto split(int x){
85+
auto p=t.lower_bound({x});
86+
if(p!=t.end()&&p->l==x){
87+
return p;
88+
}
89+
p=prev(p);
90+
int l=p->l,r=p->r,value=p->value;
91+
t.erase(p);
92+
t.insert({l,x-1,value});
93+
return t.insert({x,r,value}).first;
94+
}
95+
void assign(int l,int r,int value){
96+
auto pr=split(r+1),pl=split(l);
97+
t.erase(pl,pr);
98+
t.insert({l,r,value});
99+
}
100+
void ascending(int l,int r){
101+
auto pr=split(r+1),pl=split(l);
102+
int cnt=0;
103+
for(auto i=pl;i!=pr;i=next(i)){
104+
if(i->value){
105+
cnt+=i->r - i->l + 1;
106+
}
107+
}
108+
assign(l,r-cnt,0);
109+
assign(r-cnt+1,r,1);
110+
}
111+
void descending(int l,int r){
112+
auto pr=split(r+1),pl=split(l);
113+
int cnt=0;
114+
for(auto i=pl;i!=pr;i=next(i)){
115+
if(i->value){
116+
cnt+=i->r - i->l + 1;
117+
}
118+
}
119+
assign(l,l+cnt-1,1);
120+
assign(l+cnt,r,0);
121+
}
122+
int perform(int x){
123+
auto pr=split(x+1),pl=split(x);
124+
return pl->value;
125+
}
126+
}t;
127+
bool check(int mid){
128+
t.clear();
129+
t.build(1,n);
130+
for(int i=1;i<=n;i++){
131+
t.assign(i,i,a[i]>=mid);
132+
}
133+
for(int i=1;i<=m;i++){
134+
switch(op[i].op){
135+
case 0:
136+
t.ascending(op[i].l,op[i].r);
137+
break;
138+
case 1:
139+
t.descending(op[i].l,op[i].r);
140+
break;
141+
}
142+
}
143+
return t.perform(q);
144+
}
145+
int main(){
146+
/*freopen("test.in","r",stdin);
147+
freopen("test.out","w",stdout);*/
148+
149+
ios::sync_with_stdio(false);
150+
cin.tie(0);cout.tie(0);
151+
152+
cin>>n>>m;
153+
for(int i=1;i<=n;i++){
154+
cin>>a[i];
155+
}
156+
for(int i=1;i<=m;i++){
157+
cin>>op[i].op>>op[i].l>>op[i].r;
158+
}
159+
cin>>q;
160+
int l=0,r=n;
161+
while(l<r){
162+
int mid=l+r+1>>1;
163+
if(check(mid)){
164+
l=mid;
165+
}else{
166+
r=mid-1;
167+
}
168+
}
169+
cout<<l<<'\n';
170+
171+
cout.flush();
172+
173+
/*fclose(stdin);
174+
fclose(stdout);*/
175+
return 0;
176+
}
177+
```

_posts/2025-8-18-2.md

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
---
2+
layout: post
3+
title: "题解:[SDOI2015] 约数个数和"
4+
subtitle: "洛谷P3327"
5+
date: 2025-8-18
6+
author: "TH911"
7+
header-img: "img/2024/10/006.jpeg"
8+
header-mask: 0.4
9+
tags:
10+
- 题解
11+
- 省选/NOI−
12+
- 数论
13+
words:
14+
- 莫比乌斯反演
15+
---
16+
17+
> [题目传送门](https://www.luogu.com.cn/problem/P3327)
18+
19+
# 题意分析
20+
21+
不妨令 $n\leq m$。
22+
23+
首先,答案为:
24+
25+
$$
26+
\sum_{i=1}^n\sum_{j=1}^md(ij)
27+
$$
28+
29+
这个 $d(ij)$ 表示 $ij$ 的**约数个数**,很不好处理。
30+
31+
因此可以考虑 $d(ij)$ 能否化简,有:
32+
33+
$$
34+
d(ij)=\sum_{x\mid i}\sum_{y\mid i}[x\perp y]
35+
$$
36+
37+
证明参见[此处](./Number-Theory#常见积性函数)
38+
39+
因此可以进行推导。记答案为 $\textit{ans}$
40+
41+
$$
42+
\begin{aligned}
43+
\textit{ans}&=\sum_{i=1}^n\sum_{j=1}^m\sum_{x\mid i}\sum_{y\mid i}[x\perp y]\\
44+
&=\sum_{x=1}^n\sum_{y=1}^m[x\perp y]\sum_{i=1}^{\left\lfloor\frac nx\right\rfloor}\sum_{j=1}^{\left\lfloor\frac my\right\rfloor}1\\
45+
&=\sum_{x=1}^n\sum_{y=1}^m[x\perp y]\left\lfloor\frac nx\right\rfloor\left\lfloor\frac my\right\rfloor\\
46+
&=\sum_{x=1}^n\sum_{y=1}^m\sum_{t\mid\gcd(x,y)}\mu(t)\left\lfloor\frac nx\right\rfloor\left\lfloor\frac my\right\rfloor\\
47+
&=\sum_{t=1}^n\mu(t)\sum_{x=1}^{\left\lfloor\frac nt\right\rfloor}\sum_{y=1}^{\left\lfloor\frac mt\right\rfloor}\left\lfloor\frac n{xt}\right\rfloor\left\lfloor\frac m{yt}\right\rfloor\\
48+
&=\sum_{t=1}^n\mu(t)\left(\sum_{x=1}^{\left\lfloor\frac nt\right\rfloor}\left\lfloor\frac n{xt}\right\rfloor\right)\left(\sum_{y=1}^{\left\lfloor\frac mt\right\rfloor}\left\lfloor\frac m{yt}\right\rfloor\right)
49+
\end{aligned}
50+
$$
51+
预处理 $\displaystyle s_i=\sum_{x=1}^i\left\lfloor\frac ni\right\rfloor$ 即可利用数论分块 $\mathcal O(\sqrt n)$ 计算。
52+
53+
# AC 代码
54+
55+
时间复杂度:$\mathcal O(T\sqrt n)$。
56+
57+
```cpp
58+
//#include<bits/stdc++.h>
59+
#include<algorithm>
60+
#include<iostream>
61+
#include<cstring>
62+
#include<iomanip>
63+
#include<cstdio>
64+
#include<string>
65+
#include<vector>
66+
#include<cmath>
67+
#include<ctime>
68+
#include<deque>
69+
#include<queue>
70+
#include<stack>
71+
#include<list>
72+
using namespace std;
73+
typedef long long ll;
74+
constexpr const int N=50000;
75+
int mu[N+1];
76+
ll s[N+1];
77+
void pre(){
78+
static int vis[N+1],prime[N+1],size;
79+
mu[1]=1;
80+
for(int i=2;i<=N;i++){
81+
if(!vis[i]){
82+
vis[i]=i;
83+
prime[++size]=i;
84+
mu[i]=-1;
85+
}
86+
for(int j=1;j<=size&&i*prime[j]<=N;j++){
87+
vis[i*prime[j]]=prime[j];
88+
if(i%prime[j]==0){
89+
break;
90+
}
91+
mu[i*prime[j]]=-mu[i];
92+
}
93+
}
94+
for(int i=1;i<=N;i++){
95+
mu[i]+=mu[i-1];
96+
}
97+
for(int i=1;i<=N;i++){
98+
for(int l=1,r;l<=i;l=r+1){
99+
int ti=i/l;
100+
r=i/ti;
101+
s[i]+=(r-l+1ll)*ti;
102+
}
103+
}
104+
}
105+
int main(){
106+
/*freopen("test.in","r",stdin);
107+
freopen("test.out","w",stdout);*/
108+
109+
ios::sync_with_stdio(false);
110+
cin.tie(0);cout.tie(0);
111+
112+
pre();
113+
int T;
114+
cin>>T;
115+
while(T--){
116+
int n,m;
117+
cin>>n>>m;
118+
if(m>n){
119+
swap(n,m);
120+
}
121+
ll ans=0;
122+
for(int l=1,r;l<=m;l=r+1){
123+
int tn=n/l,tm=m/l;
124+
r=min(n/tn,m/tm);
125+
ans+=(mu[r]-mu[l-1])*s[tn]*s[tm];
126+
}
127+
cout<<ans<<'\n';
128+
}
129+
130+
cout.flush();
131+
132+
/*fclose(stdin);
133+
fclose(stdout);*/
134+
return 0;
135+
}
136+
```
137+

0 commit comments

Comments
 (0)