专栏文章
题解:P14352 排序
P14352题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @ming6gf4
- 此快照首次捕获于
- 2025/12/02 01:53 3 个月前
- 此快照最后确认于
- 2025/12/02 01:53 3 个月前
题目大意
给定一个长度为 的排列 ,定义排序算法 如下:
- 执行 轮操作,每轮从 到 依次检查,如果 则交换它们。
问有多少个排列在执行 后会变成完全升序的,答案对 取模。
思路
冒泡排序性质
冒泡排序有一个重要性质:
- 第 1 轮结束后,最大的元素会移动到最后一个位置。
- 第 2 轮结束后,第二大的元素会移动到倒数第二个位置。
- ...
- 第 轮结束后,前 大的元素都在它们的最终位置上。
因此,执行 轮冒泡排序后,最大的 个元素(即 )已经在它们的正确位置上。
转化
一个排列可以唯一地由其逆序表 表示,其中 表示在 右边且比 小的元素个数。
冒泡排序每轮每个元素最多左移一次,因此:
- 如果某个元素需要左移 次才能到达最终位置,那么至少需要 轮排序。
- 换句话说,如果 ,那么 轮后这个元素还没到达最终位置。
所以,排列在 轮冒泡排序后完全有序的充要条件是:对于所有 ,。
公式推导
由于 的取值范围是 到 ,加上限制 后, 的取值范围是 到 。
令 ,我们可以分两种情况:
-
当 时
- 所有排列都能在 轮内排好序。
- 答案就是 。
-
当 时
- 对于 ,,所以 有 种取值。
- 对于 ,,所以 有 种取值。
- 总方案数为:
最终公式
算法实现
- 如果 ,直接计算 (注意 不会太大,因为 )。
- 如果 ,计算 和 (用快速幂)。
- 注意取模运算。
复杂度分析
- 计算阶乘:。
- 快速幂:。
- 总复杂度:,可以处理 高达 的情况。
代码
CPP#include <bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
// 计算 a^b % MOD
long long qpow(long long a, long long b) {
long long res = 1;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int main() {
long long n, k;
cin >> n >> k;
if (k >= n) {
// k >= n 时,所有排列都能排好序。
long long ans = 1;
for (int i = 1; i <= n; i++) {
ans = ans * i % MOD;
}
cout << ans << endl;
} else {
// k < n 时,答案为 (k+1)^(n-k) * k!。
long long fact = 1;
for (int i = 1; i <= k; i++) {
fact = fact * i % MOD;
}
long long ans = fact * qpow(k + 1, n - k) % MOD;
cout << ans << endl;
}
return 0; // 好习惯。
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...