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)就可以求得,然后再遍历一遍即可找到最小交换次数的序列对。此次证完。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值