C. Insertion Sort

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.

Examples
input
5
4 0 3 1 2
output
3 2
input
5
1 2 3 4 0
output

 
3 4
Note

In the first sample the appropriate pairs are (0, 3) and (0, 4).

In the second sample the appropriate pairs are (0, 4), (1, 4), (2, 4) and (3, 4).

题意:给出n个数,范围0到n-1,然后给出一个插入排序的代码,可以交换两个数,然后使交换后的排列使用交换函数的次数最少,然后问交换后的排列的调用交换函数最少次数是多少

和能有几个索引对交换可以的到最少

思路:首先它的范围只有5000,然后我们看到那个插入排序想想,他只有前面大于后面的就要交换一次,所以没交换的时候的次数其实就是整个排列的逆序数,然后我们其实考虑的就是

交换一个索引使得他的逆序对个数减少最多,然后求有几个这样的索引即可,逆序数这部分我们可以使用树状数组求,我们枚举每个索引,只有前面这个数大于后面的时候我们才要考虑

是否要交换

给出一个例子

4 5 0 2 3 7 1

然后我们当前访问的索引对是(0, 7)-〉4 1

然后我们如何计算4 1交换后能减少多少个逆序对呢

首先我们如果交换 4 1的话 中间那些比4大的数的逆序对肯定不会改变,因为这些数都是大于4的,我把1 4交换,4还是小于那些数,这些逆序对就不会改变了

小于1的数也不用考虑,因为例子中的4 1交换,中间那个0还是小于1,逆序对还是存在,所以并 没有改变

所以我们只要考虑那些小于4大于1的数(a[j]<x<a[i])

我们用树状数组来优化处理

把中间小于4的数都入树状数组

然后是1的时候,我们找出大于1的数有多少然后我们可以找到2 3这两个数

然后我们把4 和1交换之后,中间那些小于4大于1的数因为大于他们的4到了后面,他们的逆序对都-1,还有1移到了2 3这些数前面,所以又要减去这么多逆序对数

总的就是   a[j]<x<a[i] 的两倍

#include<cstdio>
#include<cstring>
using namespace std;
int n,a[];
int f[];
int lowbit(int x)
{
return x&(-x);
}
int add(int x)
{
while(x)
{
f[x]++;
x-=lowbit(x);
}
}
int query(int x)
{
int sum=;
while(x<=n)
{
sum+=f[x];
x+=lowbit(x);
}
return sum;
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d",&a[i]);
a[i]++;
}
int s=;
int mx=,cs=;
for(int i=;i<=n;i++)
{
memset(f,,sizeof(f)); //把之前树状数组的数清空
for(int j=i+;j<=n;j++)
{
if(a[i]>a[j])
{
s++;//存的是总的逆序对个数
int num=+*query(a[j]);//求得能减去的逆序对个数,+1是因为当前还没有入树状数组
if(num>mx)//大于更新
{
mx=num;
cs=;
}
else if(num==mx) //等于得时候说明索引对又新加了一对
{
cs++;
}
add(a[j]);
}
}
}
printf("%d %d",s-mx,cs);
}

Codeforces Round #212 (Div. 2) C. Insertion Sort的更多相关文章

  1. 贪心/数学 Codeforces Round #212 (Div. 2) A. Two Semiknights Meet

    题目传送门 /* 贪心/数学:还以为是BFS,其实x1 + 4 * k = x2, y1 + 4 * l = y2 */ #include <cstdio> #include <al ...

  2. Codeforces Round #486 (Div. 3)-B. Substrings Sort

    B. Substrings Sort time limit per test 1 second memory limit per test 256 megabytes input standard i ...

  3. Codeforces Round #648 (Div. 2) B. Trouble Sort

    一开始读错题了...想当然地认为只能相邻元素交换...(然后换了两种写法WA了4发,5分钟切A的优势荡然无存) 题目链接:https://codeforces.com/contest/1365/pro ...

  4. Codeforces Round #198 (Div. 2) D. Bubble Sort Graph (转化为最长非降子序列)

    D. Bubble Sort Graph time limit per test 1 second memory limit per test 256 megabytes input standard ...

  5. Codeforces Round #650 (Div. 3) F1. Flying Sort (Easy Version) (离散化,贪心)

    题意:有一组数,每次操作可以将某个数移到头部或者尾部,问最少操作多少次使得这组数非递减. 题解:先离散化将每个数映射为排序后所对应的位置,然后贪心,求最长连续子序列的长度,那么最少的操作次数一定为\( ...

  6. Codeforces Round #212 (Div. 2) D. Fools and Foolproof Roads 并查集+优先队列

    D. Fools and Foolproof Roads   You must have heard all about the Foolland on your Geography lessons. ...

  7. Codeforces Round 212 Div 2 报告(以前没写完,现在也没心情补了,先就这样吧)

    A. Two Semiknights Meet 题目大意:有一个8x8的棋盘,上面放有两个骑士,骑士以“田字”的方式走.每个方格都被定义为good或者bad,问骑士能否在good的格子中相遇? 由于骑 ...

  8. Codeforces Round #258 (Div. 2) 小结

    A. Game With Sticks (451A) 水题一道,事实上无论你选取哪一个交叉点,结果都是行数列数都减一,那如今就是谁先减到行.列有一个为0,那么谁就赢了.因为Akshat先选,因此假设行 ...

  9. cf之路,1,Codeforces Round #345 (Div. 2)

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

随机推荐

  1. 利用WCF实现上传下载文件服务

    使用WCF上传文件           在WCF没出现之前,我一直使用用WebService来上传文件,我不知道别人为什么要这么做,因为我们的文件服务器和网站后台和网站前台都不在同一个机器,操作人员觉 ...

  2. LeetCode--389--找不同

    问题描述: 给定两个字符串 s 和 t,它们只包含小写字母. 字符串 t 由字符串 s 随机重排,然后在随机位置添加一个字母. 请找出在 t 中被添加的字母. 示例: 输入: s = "ab ...

  3. android AIDL 语言用法

    跨进程通信可以用AIDL语言 这里讲述下如何使用AIDL语言进行跨进程通信 文章参考 <设计模式>一书 demo结构参考 主要的文件类有:IBankAidl.aidl java文件:Aid ...

  4. Confluence 6 指派和撤销空间权限

    指派空间权限 希望添加一个新用户或者用户组到权限列表中,从希望选择的选项中查找用户组或者用户,然后选择 添加(Add).用户和用户组将会显示在列表中:选择你希望引用的权限,然后选择 保存所有(Save ...

  5. redis,memcache二者的区别是?(优缺点)

    Memcache和Redis区别: Redis中,并不是所有的数据都一直存储在内存中的,这是和Memcache相比一个最大的区别. Redis在很多方面具备数据库的特征,或者说就是一个数据库系统,而M ...

  6. MySql之行记录的详细操作,创建用户以及库表的授权

    一 介绍 MySQL数据操作: DML ======================================================== 在MySQL管理软件中,可以通过SQL语句中的 ...

  7. SQL SERVER select,update,delete使用表别名

    [SELECT] select * from 表名 表别名 [UPDATE] update 表别名 set 表别名.列=值 from 表名 表别名 where 条件 [DELETE] delete 表 ...

  8. python记录_day03 字符串

    python基本数据类型回顾 1. int 整数 2. str 字符串. 不会用字符串保存大量的数据 3. bool 布尔值. True, False 4. list 列表(重点) 存放大量的数据 5 ...

  9. ACM-ICPC 2018 南京赛区网络预赛Skr

    题意:求本质不同的回文子串的和 题解:先构造pam,然后根据pam的原理(ch表示在该节点表示的回文串两侧加上该字符)对于每个节点维护一个表示该节点字符串的值,加起来即可 //#pragma GCC ...

  10. poj-2888-矩阵+polya

    Magic Bracelet Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 6195   Accepted: 1969 D ...