D. Yet Another Sorting Problem

博客围绕数组排序问题展开,给定数组,可选择三元组循环移动元素,判断能否使数组非递减。思路是先分析三元组移动结果,发现操作对逆序对奇偶性的影响,再考虑数相同的情况,通过特判相同数和统计逆序对奇偶性来判断是否可行。

D. Yet Another Sorting Problem

Problem - D - Codeforces

题意

给你一个数组,每次你可以选择一个三元组 ( i , j , k ) (i,j,k) (i,j,k)然后将 a i , a j , a k a_i,a_j,a_k ai,aj,ak 循环移动依次,问你是否可以通过若干次操作将该数组变成非递减的。

思路

  • 思维

​ 首先假设三个位置是 1 , 2 , 3 1,2,3 1,2,3,可以发现你将第一个数放到某个地方之后 后续的移动就已经固定了(因为要形成要给三元环),因此可能的结果只有 2 , 3 , 1 2,3,1 2,3,1 3 , 1 , 2 3,1,2 3,1,2两种。

​ 如何判断是否合法?最简单的方式就是模拟一遍,从左向右一个一个复原,但是你发现 搞成 2 , 3 , 1 2,3,1 2,3,1更优,还是 3 , 1 , 2 3,1,2 3,1,2更优是不确定的。因此再观察一下性质,发现这两种方式都只会让逆序对 + 2 / − 2 +2/-2 +2/2也就是你操作一次对总逆序对的奇偶性不产生改变,所以启迪我们直接从逆序对入手,直接判断是否可行。

​ 然后我们刚才的考虑情况是默认三个数均不同的,发现如果三个数里存在一样的,逆序对就可能产生奇数变化,这样的话一定有解了。

​ 因此特判是否有相同的,然后统计一下逆序对,判断奇偶性即可。

Code

#include <bits/stdc++.h>
#define x first
#define y second
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
typedef unsigned long long ULL;
const int N = 5e5 + 10, M = 2 * N, INF = 0x3f3f3f3f, mod = 1e9 + 7;
const double eps = 1e-8, pi = acos(-1), inf = 1e20;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int h[N], e[M], ne[M], w[M], idx;
void add(int a, int b, int v = 0) {
	e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx ++;
}
int n, m, k;
int a[N];
bool st[N];
int tr[N];
void add(int x) {
	for (; x <= n; x += x & -x) tr[x] ++;
}
int sum(int x) {
	int res = 0;
	for (; x; x -= x & -x) res += tr[x];
	return res;
}
int main() {
	ios::sync_with_stdio(false), cin.tie(0);
	int T;
	cin >> T;
	while (T -- ) {
		cin >> n;
		for (int i = 1; i <= n; i ++) st[i] = false, tr[i] = 0;
		bool ok = false;
		for (int i = 1; i <= n; i ++) {
			cin >> a[i];
			if (st[a[i]]) ok = true;
			st[a[i]] = true;
		}

		if (ok) {
			cout << "YES\n";
			continue ;
		}
		LL s = 0;
		for (int i = n; i; i --) {
			s += sum(a[i]);
			add(a[i]);
		}

		if (s & 1) cout << "NO\n";
		else cout << "YES\n";
	}
	return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值