本文介绍: 绿题?

[ICPC2021 Nanjing R] Paimon Sorting

传送门

题面翻译

给出一个排序算法(用伪代码表示):

// 排序算法
SORT(A)
  for i from 1 to n // n 是序列 A 的元素个数
    for j from 1 to n
      if a[i] < a[j] // a[i] 是序列 A 的第 i 个元素
        Swap a[i] and a[j]

请你算出对于一个序列

A

=

a

1

,

a

2

,


,

a

n

A=a_1,a_2,cdots,a_n

A=a1,a2,,an 的所有前缀

A

k

=

a

1

,

a

2

,


,

a

k

A_k=a_1,a_2,cdots,a_k

Ak=a1,a2,,ak

1

k

n

1le kle n

1kn),

SORT

(

A

k

)

operatorname{SORT}(A_k)

SORT(Ak) 中的交换(Swap)操作将会被执行几次。

题目描述

Paimon just invents a new sorting algorithm which looks much like

bubble

 

sort

textit{bubble sort}

bubble sort, with a few differences. It accepts a

1

1

1-indexed sequence

A

A

A of length

n

n

n and sorts it. Its pseudo-code is shown below.

// The Sorting Algorithm
SORT(A)
  for i from 1 to n // n is the number of elements if A
    for j from 1 to n
      if a[i] < a[j] // a[i] is the i-th element in A
        Swap a[i] and a[j]

If you don’t believe this piece of algorithm can sort a sequence it will also be your task to prove it. Anyway here comes the question:

Given an integer sequence

A

=

a

1

,

a

2

,


,

a

n

A = a_1, a_2, cdots, a_n

A=a1,a2,,an of length

n

n

n, for each of its prefix

A

k

A_k

Ak of length

k

k

k (that is, for each

1

k

n

1 le k le n

1kn, consider the subsequence

A

k

=

a

1

,

a

2

,


,

a

k

A_k = a_1, a_2, cdots, a_k

Ak=a1,a2,,ak), count the number of swaps performed if we call

SORT

(

A

k

)

text{SORT}(A_k)

SORT(Ak).

输入格式

There are multiple test cases. The first line of the input contains an integer

T

T

T indicating the number of test cases. For each test case:

The first line contains an integer

n

n

n (

1

n

1

0

5

1 le n le 10^5

1n105) indicating the length of the sequence.

The second line contains

n

n

n integers

a

1

,

a

2

,


,

a

n

a_1, a_2, cdots, a_n

a1,a2,,an (

1

a

i

n

1 le a_i le n

1ain) indicating the given sequence.

It’s guaranteed that the sum of

n

n

n of all test cases will not exceed

1

0

6

10^6

106.

输出格式

For each test case output one line containing

n

n

n integers

s

1

,

s

2

,


,

s

n

s_1, s_2, cdots, s_n

s1,s2,,sn separated by a space, where

s

i

s_i

si is the number of swaps performed if we call

SORT

(

A

i

)

text{SORT}(A_i)

SORT(Ai).

Please, DO NOT output extra spaces at the end of each line or your solution may be considered incorrect!

样例 #1

样例输入 #1

3
5
2 3 2 1 5
3
1 2 3
1
1

样例输出 #1

0 2 3 5 7
0 2 4
0

以上由米哈游赞助

以上由米哈游赞助

以上由米哈游赞助(注意题目标题:Paimon?)

解题思路

分类讨论

  • 对于每个长度的第一轮循环之后,结果是将其严格单增序列相对位置后移,之后第

    2

    ,

    3

    2,3dots

    2,3 轮排序的交换次数就是前

    i

    i

    i 个比

    a

    i

    a_i

    ai 大的个数,该操作有去重效果。 因此为了获得最后的解,在扫描的时候可以直接处理,保证每次只获得当前长度下第一次循环的结果,当遇到

    a

    i

    >

    a

    1

    a_i>a_1

    ai>a1 时,就交换

    a

    i

    a_i

    ai

    a

    1

    a_1

    a1 的位置,这就是一次必要的交换,计数器增加

    1

    1

    1,然后对于每个在线处理输入的

    a

    i

    a_i

    ai,统计先前比它大的个数,直接加上即可。 但是,当录入的

    a

    i

    a_i

    ai

    a

    1

    a_1

    a1 相等(

    a

    1

    a_1

    a1 为当前最大值)(设值为

    x

    x

    x)并且后面存在比

    a

    1

    a_1

    a1 更大的数(设值为

    y

    y

    y),那么在后面的长度当中,第一轮排序会使得当前的

    a

    i

    a_i

    ai 的值不变,而

    a

    1

    a_1

    a1 对应的值被移到了更大的数位置上,(形象一些就是这样:

    x

    ,

    x

    ,

    y

    y

    ,

    x

    ,

    x

    x,x,y→y,x,x

    x,x,yy,x,x)那么在插入

    y

    y

    y 之后,由于

    y

    y

    y 向前移动了,

    y

    y

    y

    x

    x

    x 也有一个需要交换的贡献,举例如下,假设当前长度构造的序列为:

    x

    ,

    a

    ,

    a

    ,

    a

    ,

    x

    ,

    x

    1

    ,

    x

    2

    ,

    x

    1

    x,a,a,a,x,x−1,x−2,x−1

    x,a,a,a,x,x1,x2,x1,那么插入

    y

    y

    y 之后,由于

    y

    y

    y 大于

    x

    x

    x,则变为了:

    y

    ,

    a

    ,

    a

    ,

    a

    ,

    x

    ,

    x

    1

    ,

    x

    2

    ,

    x

    1

    ,

    x

    y,a,a,a,x,x−1,x−2,x−1,x

    y,a,a,a,x,x1,x2,x1,x。那么对于

    x

    ,

    x

    1

    ,

    x

    2

    ,

    x

    1

    x,x−1,x−2,x−1

    x,x1,x2,x1 这几个数,都需要加上

    y

    y

    y

    y

    y

    y 的这个贡献,所以需要增加一个计数器(cnt),记录第二个

    x

    x

    x

    y

    y

    y 间有几个数,插入

    y

    y

    y 的时候结果加上计数器值即可。

  • 对于序列所有元素各不相同的情况,首先从第一个元素开始,找到并跳到当前元素右边第一个比它大的元素。称这些元素为“特殊元素”。可以发现外层循环的第一轮会把所有特殊元素右移一位,此时序列中最大的元素就到了序列第一个。
    从外层第二轮循环开始,对于第

    i

    i

    i 轮循环,序列前

    (

    i

    1

    )

    (i−1)

    (i1) 个元素已经是有序的。设此时第一个比

    a

    i

    a_i

    ai 大的元素是

    a

    k

    a_k

    ak​ ,那么第

    i

    i

    i 轮循环将会发生

    (

    i

    k

    )

    (i−k)

    (ik) 次交换。因此,非特殊元素将会贡献“前面有几个数比它大”次交换,但一开始特殊元素的右移对答案没有影响,因为虽然移走了一个比它大的元素,但是最大的元素移到了开头,而特殊元素将会贡献

    2

    2

    2 次交换。

  • 对于存在相同元素的情况,对非特殊元素,前面比它大的,但是相同的元素只会发生一次交换,因此需要对元素去重一下再统计。另外,如果这个非特殊元素恰好等于上一个特殊元素,那么上一个特殊元素的右移会导致该非特殊元素的贡献加

    1

    1

    1

这么长题解不想看?那就给我看完。

AC Code

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int Maxn = 1e5 + 5;
int n, a[Maxn];
int Tree[Maxn];
bool vis[Maxn];
inline int lowbit(int x) {
	return x & (-x);
}
inline void Add(int x) {
	for (int i = x; i <= n; i += lowbit(i)) {
		Tree[i]++;
	}
}
inline int Sum(int x) {
	int tot = 0;
	for (int i = x; i; i -= lowbit(i)) {
		tot += Tree[i];
	}
	return tot;
}
inline void solve() {
	memset(Tree, 0, sizeof(Tree));
	memset(vis, 0, sizeof(vis));
	cin >> n;
	int res = 0, cnt = 0;
	bool flag = 0;
	for (int i = 1; i <= n; i++) {
		cin >> a[i];
	}
	cout << 0;
	vis[a[1]] = 1;
	Add(a[1]);
	for (int i = 2; i <= n; i++) {
		if (!vis[a[i]]) {
			vis[a[i]] = 1;
			Add(a[i]);
		}
		if (a[i] == a[1]) {
			flag = 1;
		}
		cnt += flag - (flag ? a[i] > a[1] : 0);
		if (a[i] > a[1]) {
			res += cnt + 1;
			swap(a[1], a[i]);
			cnt = flag = 0;
		}
		res += Sum(a[1]) - Sum(a[i]);
		cout << " " << res;
	}
	cout << endl;
}
inline void work() {
	int T;
	cin >> T;
	while (T--) {
		solve();
	}
}
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	work();
	return 0;
}

原文地址:https://blog.csdn.net/BestMonkey/article/details/135621764

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_59230.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注