Codeforces Round #212 (Div. 2) 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.
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.
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.
5
4 0 3 1 2
3 2
5
1 2 3 4 0
3 4
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的更多相关文章
- 贪心/数学 Codeforces Round #212 (Div. 2) A. Two Semiknights Meet
题目传送门 /* 贪心/数学:还以为是BFS,其实x1 + 4 * k = x2, y1 + 4 * l = y2 */ #include <cstdio> #include <al ...
- 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 ...
- Codeforces Round #648 (Div. 2) B. Trouble Sort
一开始读错题了...想当然地认为只能相邻元素交换...(然后换了两种写法WA了4发,5分钟切A的优势荡然无存) 题目链接:https://codeforces.com/contest/1365/pro ...
- 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 ...
- Codeforces Round #650 (Div. 3) F1. Flying Sort (Easy Version) (离散化,贪心)
题意:有一组数,每次操作可以将某个数移到头部或者尾部,问最少操作多少次使得这组数非递减. 题解:先离散化将每个数映射为排序后所对应的位置,然后贪心,求最长连续子序列的长度,那么最少的操作次数一定为\( ...
- 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. ...
- Codeforces Round 212 Div 2 报告(以前没写完,现在也没心情补了,先就这样吧)
A. Two Semiknights Meet 题目大意:有一个8x8的棋盘,上面放有两个骑士,骑士以“田字”的方式走.每个方格都被定义为good或者bad,问骑士能否在good的格子中相遇? 由于骑 ...
- Codeforces Round #258 (Div. 2) 小结
A. Game With Sticks (451A) 水题一道,事实上无论你选取哪一个交叉点,结果都是行数列数都减一,那如今就是谁先减到行.列有一个为0,那么谁就赢了.因为Akshat先选,因此假设行 ...
- cf之路,1,Codeforces Round #345 (Div. 2)
cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅..... ...
随机推荐
- uva10564
路径条数很好找.记录最小路径,就记录到各点的最小字符串,存储起来. #include <iostream> #include <cstdio> #include <cma ...
- Linux中磁盘mbr分区——实践篇
Linux中磁盘mbr分区——实践篇 fdisk命令 语法 fdisk(选项)(参数) 选项 -b <分区大小> 指定每个分区的大小 -l 列出分区表信息 -v 显示版本信息 参数 设备文 ...
- 『计算机视觉』Mask-RCNN
一.Mask-RCNN流程 Mask R-CNN是一个实例分割(Instance segmentation)算法,通过增加不同的分支,可以完成目标分类.目标检测.语义分割.实例分割.人体姿势识别等多种 ...
- 漏洞复现——bash远程解析命令执行漏洞
漏洞描述:Bash脚本在解析某些特殊字符串时出现逻辑错误导致可以执行后面的命令,在一些cgi脚本中,数据是通过环境变量来传递的,这样就会形成该漏洞 漏洞原理:bash通过以函数名作为环境变量名,以“( ...
- vue嵌套路由--params传递参数
在嵌套路由中,父路由向子路由传值除了query外,还有params,params传值有两种情况,一种是值在url中显示,另一种是值不显示在url中. 1.显示在url中index.html <d ...
- chrome 浏览器去掉输入框背景透明色
chrome浏览器选择记住密码的账号,输入框会自动加上黄色的背景,有些设计输入框是透明背景的,需要去除掉这个黄色的背景: 这个黄色背景是谷歌浏览器默认的样式 user agent stylesheet ...
- C++的面试题
1.什么是类? 类是具有相同属性和相同的方法的对象的集合,它是一种既包含数据又包含函数的抽象数据类型. 对象是类进行实体化后的产物,是一个实体. 在C++中也是先声明一个类类型,用类去定义若干个同类型 ...
- PAT 1050 String Subtraction
1050 String Subtraction (20 分) Given two strings S1 and S2, S=S1−S2 is defined to be t ...
- Python装饰器--decorator
装饰器 装饰器实质是一个函数,其作用就是在不改动其它函数代码的情况下,增加一些功能.如果我们需要打印函数调用前后日志,可以这么做 def log(func): print('%s is running ...
- 【LeetCode】区间合并
给定一组区间,将所有区间重叠的部分合并起来. e.g. 给出 { [1, 3], [2, 6], [8, 10], [15, 18] },返回 { [1, 6], [8, 10], [15, 18] ...