为了更好的阅读体检,可以查看我的算法学习网
在线评测链接:P1054
题目内容
塔子哥是一个程序员,他正在为一个新的项目编写代码。这个项目需要对一个数组进行操作,但是这个数组的初始值不满足项目的要求。于是,塔子哥想到了一个办法:他可以修改数组中的任意一个元素,将其修改为任意值。他希望用最少的操作方式使得数组满足以下条件:
-
最终数组仍是一个排列。
-
最终数组的逆序对数量为 1 1 1 。
数组的逆序对是指,满足 i < j i \lt j i<j 且 a i > a j a_i \gt a_j ai>aj 的二元组数量。
排列指长度为 n n n 的数组, 1 1 1 到 n n n 每个正整数恰好出现 1 1 1 次。
输入描述
第一行输入一个正整数 n n n ,代表数组的大小。
第二行输入 n n n 个正整数 a i a_i ai ,代表塔子哥拿到的数组。
2 ≤ n ≤ 1 0 5 2\le n\le 10^5 2≤n≤105
1 ≤ a i ≤ n 1\le a_i\le n 1≤ai≤n
保证初始数组是一个排列。
输出描述
一个整数,代表最小的操作次数。
样例
样例一:
输入
4
3 2 1 4
输出
3
样例解释
将数组修改为 [2,1]
即可。
思路
逆序对只有一对的排列只能是从1~n中交换相邻的一对,比如:1、2、3、5、4、6这样的,所以直接枚举所有的符合条件的排列即可,先计算一下原排列和1~n中相同的位置有多少,然后再枚举交换相邻的一对的位置,再特殊处理一下,过程中取最小值即可。
代码
c++
#include <bits/stdc++.h>
using namespace std;
int n;
int a[100010];
int main()
{
cin >> n;
int cnt = 0;
for(int i = 1 ; i <= n ; i ++) {
cin >> a[i];
cnt += a[i]==i; //计算相同的位置
}
int ans = n;
for(int i = 1 ; i < n ; i ++) {
int t = cnt;
t -= a[i]==i; //特殊处理当前交换的i和i+1,要先去除原来的计算结果,再加上交换后的结果
t -= a[i+1]==i+1;
t += a[i]==i+1;
t += a[i+1]==i;
ans = min(ans, n-t);
}
cout << ans << endl;
}
python
n = int(input())
a = [0] + list(map(int, input().split()))
cnt = 0
for i in range(1, n+1):
a[i] == i:
cnt += 1
ans = n
for i in range(1, n):
t = cnt
if a[i] == i:
t -= 1
if a[i+1] == i+1:
t -= 1
if a[i] == i+1:
t += 1
if a[i+1] == i:
t += 1
ans = min(ans, n-t)
print(ans)
题目内容均收集自互联网,如如若此项内容侵犯了原著者的合法权益,可联系我: (CSDN网站注册用户名: 塔子哥学算法) 进行删除。