Insertion Sort (Codeforces Round #212 (Div. 2))

Petya is a beginner programmer. He has already mastered the basics of the C++ language and moved on to learning algorithms. The first algorithm he encountered was insertion sort. Petya has already written the code that implements this algorithm and sorts the given integer zero-indexed array a of size n in the non-decreasing order.

for (int i = 1; i < n; i = i + 1)
{
   int j = i; 
   while (j > 0 && a[j] < a[j - 1])
   {
      swap(a[j], a[j - 1]); // swap elements a[j] and a[j - 1]
      j = j - 1;
   }
}

Petya uses this algorithm only for sorting of arrays that are permutations of numbers from 0 to n - 1. He has already chosen the permutation he wants to sort but he first decided to swap some two of its elements. Petya wants to choose these elements in such a way that the number of times the sorting executes function swap, was minimum. Help Petya find out the number of ways in which he can make the swap and fulfill this requirement.

It is guaranteed that it's always possible to swap two elements of the input permutation in such a way that the number of swap function calls decreases.

Input

The first line contains a single integer n (2 ≤ n ≤ 5000) — the length of the permutation. The second line contains n different integers from 0 to n - 1, inclusive — the actual permutation.

Output

Print two integers: the minimum number of times the swap function is executed and the number of such pairs (i, j) that swapping the elements of the input permutation with indexes i and j leads to the minimum number of the executions.

解题思路:

1) 插入排序需要的交换次数是固定的,计算需要O(n),但遍历所有两个数交互,并求得交互次数需要O(n2),会超时。

2) 每交换两个数,将导致交换次数增加或者减少,很显然需要将小数放前面,大数放后面,这个可用于优化

3)考虑交换两个数之后对交换次数的影响,进行归纳总结

假设原排列A为 a1,a2,a3,……ai,……,aj,……an, 总的交换次数为ans,可遍历求出

则交换ai和aj之后排序B变为 a1,a2,a3……,aj,……,ai,……an。

4) 下面需要考虑当ai和aj位置交换之后带来的交换次数变动

   4.1 ai带来的交换次数变动: 排列A->B中,则a(i+1)->a(j-1)中比ai小的数相对ai都不需要变动,而比ai大的数相对ai需要变动

         假设a(i+1)->a(j-1)中比ai小的数有M个,区间的数共有K个,则比ai大的数有K-M个;

         则ai变动之后,暂不考虑aj,交换次数变为ans-M+(K-M)=ans+K-2*M

   4.2 同理可得aj带来的交换次数变动:a(i+1)->a(j-1)中比aj大的数相对aj都不需要变动,而比aj小的数相对aj需要变动,与ai正好相反

         为了保持一致,也假设a(i+1)->a(j-1)中比aj小的数有M1个,区间的数共有K个,则比aj大的数有K-M1个;

         则aj变动之后,暂不考虑ai,交换次数ans-(K-M1)+M1,=ans-K+2*M1

  4.3 ai和aj交换,带来的交换次数变动 (aj>ai) - (ai>aj)。

5)综上可得,ai和aj交换之后,总的交换次数变动为 up_ans =  ans+K-2*M-K+2*M1 = ans + 2*(M1-M)

思路分析完毕,下面需要对M1和M进行处理,M1为a(i+1)->a(j-1)之间比aj小的数个数,M为比ai小的数的个数,则我们可以设置一个函数f(N)(M)来表示N+1(或者N-1,M可能比N小)到M之间比a(N)小的个数,则M表示为f(i)(j-1),M1表示为f(j)(i+1)

对于f(N)(M)函数求法,可以用动态规划的方式求得;如M>N,则 f(N)(M)=f(N)(M-1)+(am<an)。 反之  f(N)(M)=f(N)(M+1)+(am<an)

6) 每两个数交换之后的交换次数通过O(n)就可以求得,然后再遍历一遍即可找到最小交换次数的序列对。此次证完。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java实现插入排序可以使用以下代码: private static void insertionSort(int[] arr) { int len = arr.length; int temp, j; for (int i = 1; i < len; i++) { temp = arr[i]; j = i - 1; while (j >= 0 && arr[j] > temp) { arr[j + 1] = arr[j]; j--; } arr[j + 1] = temp; } System.out.println(Arrays.toString(arr)); } 这段代码使用了插入排序的算法。它首先将数组分为已排序和未排序两部分,然后从未排序部分选择一个元素,将其插入到已排序部分的正确位置。在每次迭代中,将当前元素与已排序部分的元素进行比较,如果当前元素比已排序部分的元素小,则将已排序部分的元素向后移动,然后将当前元素插入到正确的位置。 以上是一种基本的插入排序算法实现,通过比较数组中的相邻元素进行排序。这种算法的时间复杂度为O(n^2),其中n是数组的长度。可以根据实际情况进行性能优化,如使用二分查找来减少比较的次数,或者使用其他排序算法来替代插入排序。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [今日算法解读之Java版插入排序Insertion Sort)](https://blog.csdn.net/qq_42349895/article/details/117304461)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值