安吉D16 T4
1338 字
7 分钟
安吉D16 T4
- 1安吉D19 T1
- 2安吉D19 T3
- 3安吉D20 模考12总结
- 4安吉D17 T3
- 5安吉D17 T4
- 6安吉D19 模考11总结
- 7安吉D15 A
- 8安吉D16 T4本文
- 9安吉D17 T1
- 10安吉D17 模考10总结
- 11安吉D16 T3
- 12安吉D16 模考9总结
- 13安吉D13 模考8总结
- 14安吉D13-T2
- 15安吉D13-T3
- 16安吉D12-T3
- 17安吉D11-B
- 18安吉D11-C
- 19安吉D11-D
- 20安吉D12 模考7总结
- 21安吉D12-T2
- 22安吉D11-A
- 23安吉D10 模考6总结
- 24安吉D10-T3
- 25安吉D10-T4
- 26安吉D8-E
- 27安吉D9-T4
- 28安吉D8-A
- 29安吉D8-B
- 30安吉D8-C
- 31安吉D8-D
- 32安吉D9 模考5总结
- 33安吉D9-T2
- 34安吉D9-T3
- 35安吉D6-T4
- 36安吉D4-G
- 37安吉D5-T2
- 38安吉D6 模考4总结
- 39安吉D6-T1
- 40安吉D6-T3
- 41安吉-开营测试 T4
- 42安吉D5 模考3总结
- 43安吉D5-T3
- 44安吉D4-A
- 45安吉D4-B
- 46安吉D4-C
- 47安吉D4:容斥原理
- 48安吉Day4-D
- 49安吉D3 模考2总结
- 50安吉D3-T1
- 51安吉D3-T2
- 52安吉D3-T4
- 53安吉D2 模考1总结
- 54安吉D2-T2
- 55安吉D1-G
- 56安吉D1-L
- 57安吉D2-T4
原题呈现
01 的冒泡排序
题目描述
01 学习了冒泡排序,觉得太简单,于是创造了属于自己的排序方式.
给定一个长度为 的排列 以及一个神秘数字 ,01 会执行以下操作:
- 初始令 .
- 如果当前数组已经排好序(即非降序),则停止操作.
- 否则,按 从 到 遍历:
- 若子区间 并非升序,则将该区间从小到大排序,同时令 .
- 一轮结束,回到第二步.(这一步时题解作者增加的,或许加上会更严谨一些?)
你需要求出操作结束时 的值.
输入格式
第一行输入两个整数 ,表示数组长度和神秘数字. 第二行输入 个整数 ,表示给定的排列.
输出格式
输出一行一个整数,表示最终的 值.
样例
输入样例 1
5 21 4 5 3 2输出样例 1
5数据范围
- 对于 的数据,保证 .
- 对于另 的数据,保证 .
- 对于另 的数据,保证 .
- 对于 的数据:
我们回忆冒泡排序的过程,实际上,冒泡排序每一次可以让未排序的最大的一个数归位,那么变种有没有这种性质呢?
我们尝试模拟这个流程,首先,对区间 排序,然后,丢下了最小的一个数,区间右移到 .显然,此时区间内, 里面存放的是 中前 大的 个数.将其扩展到 ,当遍历到区间 时,其中的 是 中最大的 个数.
我们来转向结束条件.题目中的结束条件是:
如果当前数组已经排好序(即非降序),则停止操作.
显然,我们不能对于每一个数,都将它和前一个数比较,这样不好维护.我们知道,一个数组是有序的当且仅当每个数前面都没有比它大的数,因此,我们定义 表示位置 之前比 大的数.这样,结束条件就从“有序”转化为了 . 可以使用树状数组快速算出.
那要如何才能使得 减小呢?我们在每一次区间右移时,区间左边的 个数都是有序的,只有最后一个数是无序的.因此,这就相当于将最后一个数插入到前面这个序列中.此时 变化如下:
- 若 ,由于当前区间只有 个数,且前 个数是当前已遍历到的最大的 个数.又因为比 大的至少也有 个.因此,这表示 是当前区间内最小的数,将 的位置前移 ,即 .
- 若 ,由于比 小的数最多也只有 个,那么这 个全在当前区间里了.这说明将当前区间进行一次排序就足以把所有比 大的数移动到 后面了,此时, 前面已经没有比 小的数了,故 .
综上所述, 需要移动 次才能移动到目标位置.当然,所有最后一次移动到区间 的数可以一次性全部排序使其回到正确的位置.故若设 , 表示当前点每一次移动 移动到区间 需要移动的次数:
- 若 ,则表示 根本不会移动到 ,或是移动到时 已经为 0,不需要集体排序.
- 若 ,则表示 在进行了 次移动后,移动到了 ,由于每一轮每一个数字最多只能移动 步一次,故此时已经过去 轮.会在第 轮预定一次 的集体排序.
特别的,一开始就在 的数若 ,则会在第一轮 的集体排序中恢复有序.
对于每一项计算移动次数加和即可.
标程
#include <bits/stdc++.h>#define int long longusing namespace std;const int N = 2e5 + 100;int n, k;int a[N];bool sfa[N];// sfa => Sort in the First Action in i th round,是否需要在第 i 轮在区间 [1,k] 进行排序
struct BIT { int f[N]; void Modify(int pos, int v) { for (int i = pos; i <= n; i += (i & (-i))) { f[i] += v; } } int query(int pos) { if (pos == 0) return 0; int ans = 0; for (int i = pos; i >= 1; i -= (i & (-i))) { ans += f[i]; } return ans; } int query(int l, int r) { return query(r) - query(l - 1); }} bit;
signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); cin >> n >> k; for (int i = 1; i <= n; i++) { cin >> a[i]; } long long cnt = 0; for (int i = 1; i <= k; i++) { int b = bit.query(a[i], n); if (b != 0) { sfa[1] = true; } bit.Modify(a[i], 1); } for (int i = k + 1; i <= n; i++) { int b = bit.query(a[i], n); bit.Modify(a[i], 1); int t1 = ceil(1.0 * b / (k - 1.0)); int t2 = ceil((i - k + 0.0) / (k - 1.0)); if (t1 <= t2) { cnt += t1; } else { cnt += t2; sfa[t2 + 1] = true; } } for (int i = 1; i <= n; i++) cnt += sfa[i]; cout << cnt; return 0;}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!


