题解:CF2123F Minimize Fixed Points
前置知识、符号与约定
前置知识
符号与约定
文中用到的非公认或非常用的符号,按出现顺序排列:
-
\([n]\):\(\{1,2,3,\ldots ,n\}\)
-
\(A \setminus B\):集合 \(A\) 与集合 \(B\) 的差
\(A \setminus B = \{x \mid x \in A \ \land \ x \not\in B \}\)
-
\(P(x)\) :\(x\) 的最大质因子
-
\(a \not\perp b\) :\(a\) 与 \(b\) 不互质
-
\(\mathbb{P}\):质数集
-
\(\operatorname{supp}(\sigma)\):轮换 \(\sigma\) 的支撑集
设 \(\sigma = (a_1\ a_2\ \cdots\ a_k)\),则 \(\operatorname{supp}(\sigma) = \{a_1, a_2, \dots, a_k\}\)
-
\(\sigma \circ \tau\):轮换 \(\sigma\) 与轮换 \(\tau\) 的乘积
若 \(\operatorname{supp}(\sigma) \cap \operatorname{supp}(\tau) = \emptyset\)(文中仅出现了这种情况),设 $\sigma = (a_1 \cdots a_k) \(,\) \tau = (b_1 \cdots b_m) $ ,则 \(\sigma \circ \tau = (a_1 \cdots a_k)(b_1 \cdots b_m)\)
-
\(\prod\):轮换的连乘积
题意
给定 \(n\),构造一个 \([n]\) 上的置换 \(p\),满足:
- \(\forall\, i \in [n] \setminus \{1\},\quad p(i) \not\perp i\);
- 最小化 \(\sum_{i=1}^{n} [p(i) = i]\)。
报告任意一个 \(p\)。可以证明,\(p\) 总是存在的。
思路
观察 1:\(\sum_{i=1}^{n} [p(i) = i]\) 的下界
注意到
是无法避免的,因此这些位置已经被固定。
证明
\(p(1) = 1\) 无法避免是因为 \(1\) 与任何数都互质。
而
无法避免是因为
因为最小的,不等于 \(x\) 的,与 \(x\) 不互质的正整数是 \(2x\)。
因此, \(\sum_{i=1}^{n} [p(i) = i]\) 的下界为 \(\left|\{1\} \cup \mathbb{P} \cap \left[\left\lceil \frac{n}{2} \right\rceil, n\right]\right|\)。
转换 1:最小化 \(\sum_{i= 1}^{n} [p(i) = i]\) 的另一种表示
设 \(p\) 的轮换分解为 \(C_1 C_2 \dots C_k\)。
若存在 \(p\) 的轮换 \(\sigma\) 满足 \(\gcd(\operatorname{supp}(\sigma)) > 1\) 且 \(|\sigma| > 1\),则有
因此在
的前提下,最小化
可转换为,在
的前提下最小化
观察 2:下界可以被取到
证明
若有
则有下界可以被取到。
我们通过直接构造 \(p\) 来证明:
其中:
- \(D_1 = (1)\) 为平凡轮换
- \(\forall \, i \in \mathbb{P} \cap [2,n]\),\(D_i\) 为满足 \(\operatorname{supp}(D_i) = \{ x \in [2,n] \mid P(x) =i \}\) 的轮换
因为有
所以有
仍需证明
注意到有
综上所述,\(p\) 符合题意要求,证毕。
算法&实现
算法
上述思路中,我们需要实现,将每个数按最大质因子“归类”。
对每个数因数分解以寻找其最大质因子,不是明智的做法。因为寻找因子是困难的,而寻找倍数是简单的。
以下伪代码展示了如何预处理每个 \(i \in [n]\) 的最大质因子。
P[1] = P[2] = ... = P[n] = 0
for (i : 从大到小遍历 [1, n] 以内质数) {
for (j = i; j <= n; j += i) if (P[j] == 0) {
P[j] = i;
}
}
P[1], P[2], ..., P[n] 即为所求,时间复杂度 \(\Theta(n \log \log n)\),空间复杂度 \(\Theta(n)\)。
代码
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 100000 + 1;
bitset<N> np;
vector<int> primes;
int p[N], cyc[N];
void solve() {
int n;
cin >> n;
for (auto itr = lower_bound(primes.begin(), primes.end(), (n + 1) >> 1, greater<>()); itr != primes.end(); ++itr) {
int i = *itr, len = 0;
for (int j = i; j <= n; j += i) if (!p[j]) {
cyc[len++] = j;
}
if (len) {
for (int j = 0; j < len; ++j) {
p[cyc[j]] = cyc[j + 1];
}
p[cyc[len - 1]] = cyc[0];
}
}
for (int i = 1; i <= n; ++i) {
cout << (p[i] ? p[i] : i) << ' ';
}
cout << '\n';
memset(p + 1, 0, sizeof(int) * n);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
for (int i = 2; i * i < N; ++i) if (!np[i]) {
for (int j = i * i; j < N; j += i) {
np[j] = true;
}
}
for (int i = 2; i < N; ++i) if (!np[i]) {
primes.push_back(i);
}
reverse(primes.begin(), primes.end());
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
复杂度分析
设 \(N\) 为 \(O(\max_{1 \leq i \leq t}{n_i})\)。
上述代码时间复杂度为 \(\Theta(N \log \log N + t \log \frac{N}{\log N} + \sum_{i=1}^t n_i \log \log n_i)\),空间复杂度为 \(\Theta(N)\)。
注意,若
for (auto itr = lower_bound(primes.begin(), primes.end(), (n + 1) >> 1, greater<>()); itr != primes.end(); ++itr)
写成
for (auto itr = primes.begin(); itr != primes.end(); ++itr)
则时间复杂度退化成 \(\Theta(N \log \log N + t\frac{N}{\log N} + \sum_{i=1}^t n_i \log \log n_i)\)。
posted on 2025-07-18 17:12 SkyWave2022 阅读(32) 评论(0) 收藏 举报
浙公网安备 33010602011771号