题解 CF351E 【Jeff and Permutation】

CF351E Jeff and Permutation

这是一道思维题。

传送门

题意分析:

给你 n 个数组成的序列,你可以对任意数进行取反操作,你需要使得这个序列的逆序对个数最少,并输出这个个数。

题解

对题目进行等价变形

不妨把这 \(n\) 个数全部取绝对值变成非负整数再考虑进行操作,显然这是等价的。

我们考虑对于序列中的某个数,它取反后对逆序对个数的影响是什么。

example :

1 3 0 1 2 3 0 2

对中间的 2 进行取反操作,不难发现:

  • 2的前面多出现了 3 个逆序对。

  • 2的后面少了 1 个逆序对。

而如果不取反:

  • 2的前面有 1 个逆序对。

  • 2的后面有 1 个逆序对。

有思路了吗???

解法:

换句话讲,对于中间(非两边)的数进行取反操作,前面比他小的数的个数就是多出现的逆序对个数,否则如果不取反,后面比它小的数就是本来该有的逆序对个数。

由于前面本来就有的逆序对个数在考虑 3 时就已经算过了,所以不用中间数前面比他大的数,我们考虑的只是新增的或者新减的逆序对个数。

Solution:

  • 每次统计两边比它小的数的个数 \(l\)\(r\)

  • 每次计数器加上他俩的 min 即可。

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,a[2005],ans;
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",a+i);
		if(a[i]<0)a[i]=-a[i];
	}
	for(int i=2;i<n;i++){
		int l=0,r=0;
		for(int j=1;j<i;j++)if(a[j]<a[i])l++;
		for(int j=i+1;j<=n;j++)if(a[j]<a[i])r++;
		ans+=min(l,r);
	}
	cout<<ans;
	return 0;
}
posted @ 2021-08-12 16:35  ¶凉笙  阅读(32)  评论(0编辑  收藏  举报