E. Permutation Sorting
E. Permutation Sorting
You are given a permutation of size . We call an index good if is satisfied. After each second, we rotate all indices that are not good to the right by one position. Formally,
- Let be the indices of that are not good in increasing order. That is, and if index is not good, then there exists such that .
- For each from to , we assign all at once.
For each from to , find the first time that index becomes good.
A permutation is an array consisting of distinct integers from to in arbitrary order. For example, is a permutation, but is not a permutation ( appears twice in the array) and is also not a permutation ( but there is in the array).
Input
Each test contains multiple test cases. The first line contains the number of test cases (). The description of the test cases follows.
The first line of each test case contains a single integer () — the size of permutation .
The second line of each test case contains integers () — the elements of permutation .
It is guaranteed that the sum of over all test cases does not exceed .
Output
For each test case, output a single line containing integers where the -th integer represents the first time that index becomes good.
Example
input
2
5
3 2 4 1 5
6
2 1 4 6 5 3
output
1 0 1 1 0
2 1 2 1 0 1
Note
In the first test case, and are already in the correct position so indices and become good at second. After second, a cyclic shift will be done with , resulting in array . Notice that indices , and become good at second.
In the second test case, is already in the correct position, so index becomes good at second. After second, a cyclic shift will be done with , resulting in array . Notice that indices , and become good at second. After seconds, a cyclic shift will be done with , resulting in array . Notice that indices and become good at second.
解题思路
为了方便将数组 的每个元素减 。定义 表示将元素 从下标 移到下标 所需要的时间,有 。同时破环成链,把数组 拷贝一份接到后面,即对于 ,有 。
考虑计算下标为 的答案,首先需要将 向右移动 个时间,假设在这个过程中存在元素 满足 且 ,即在 移动的过程中这些元素移动到其对应的下标,那么 就要跳过这些元素。假设有 个这样的元素,那么实际上 只用移动 个时间。
因此对于每个 ,只需统计出有多少个元素 满足 。可以看作是一个二维数点问题,对于每个下标 ,将 看作是一个点,那么就相当于询问左下角为 右上角为 的矩形内有多少点。
AC 代码如下,时间复杂度为 :
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, M = N * 2;
int n;
int a[N], h[M];
int tr[M];
struct Node {
int x, y, c, idx;
}p[N * 4];
int ans[N];
int lowbit(int x) {
return x & -x;
}
void add(int x, int c) {
for (int i = x; i <= n << 1; i += lowbit(i)) {
tr[i] += c;
}
}
int query(int x) {
int ret = 0;
for (int i = x; i; i -= lowbit(i)) {
ret += tr[i];
}
return ret;
}
void solve() {
scanf("%d", &n);
for (int i = 0; i < n; i++) {
scanf("%d", a + i);
a[i]--;
h[i] = h[i + n] = (a[i] - i + n) % n;
}
for (int i = 0, j = 0; i < n; i++) {
int x1 = i + 1, y1 = i + 1, x2 = i + h[i], y2 = i + h[i];
p[j++] = {x2, y2, 1, i};
p[j++] = {x1 - 1, y1 - 1, 1, i};
p[j++] = {x1 - 1, y2, -1, i};
p[j++] = {x2, y1 - 1, -1, i};
}
sort(p, p + n * 4, [&](Node &a, Node &b) {
return a.x < b.x;
});
for (int i = 0; i < n; i++) {
ans[a[i] % n] = h[i];
}
memset(tr, 0, n + 10 << 3);
for (int i = 0, j = 0; i < n << 2; i++) {
while (j < n << 1 && j <= p[i].x) {
add(j + h[j] + 1, 1); // 由于j+h[j]可能为0,因此加一个偏移量
j++;
}
ans[a[p[i].idx] % n] -= p[i].c * query(p[i].y + 1); // 同理加一个偏移量
}
for (int i = 0; i < n; i++) {
printf("%d ", ans[i]);
}
printf("\n");
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
solve();
}
return 0;
}
参考资料
CodeTON Round 7 (Div. 1 + Div. 2, Rated, Prizes!) Editorial:https://codeforces.com/blog/entry/122172
本文来自博客园,作者:onlyblues,转载请注明原文链接:https://www.cnblogs.com/onlyblues/p/17870634.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效