• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
jacklee404
Never Stop!
博客园    首页    新随笔    联系   管理    订阅  订阅
edu#142 - Min Max Sort 思维+二分

题目

Min Max Sort

思路

​1. 若序列合法

​2. 那么最后一次操作一定用到最大值和最小值

  1. 去掉最大值和最小值, 继续操作1

​ 每次都保证一定会用到该值,所以保证解是正确的, 当时做的时候一直想不开,看了大佬的题解幡然醒悟。

现在问题转化为如何更快的检查序列是否合法?显然暴力的话\(O(n^2)\)肯定会超时。

​ 能不能二分找答案?

​ 因为答案所在的区间一定是\([0, n/2]\), 最坏的情况下将每一个数对都排以下。假设答案是操作\(x\)次,则区间\([x, n - x]\) (这里表示从1~n枚举)必然合法,并且若操作\(x + 1\)次,则\([x + 1, n - x - 1]\)为操作\(x\)的子区间也合法,只有小于\(x\)才不合法,所以具有二段性。

复杂度\(O(nlogn)\)

参考:清风qwq

Code

#include <bits/stdc++.h>

using i64 = long long;

int n;

std::vector<int> a;

// 检查 1~n中属于区间[l,r]的数时候排序合法
bool check(int l, int r) {
	int st = l;
	for(int i = 1; i <= n; i ++) {
		if(a[i] >= l && a[i] <= r) {
			if(a[i] != st) return false;
			st ++;
		}
	}
	return true;
}

void solve() {
	std::cin >> n;

	a.resize(n + 1, 0);

	for(int i = 1; i <= n; i ++) {
		std::cin >> a[i];
	}

	int l = 0, r = n / 2;

	while(l < r) {
		int mid = l + r >> 1;
		if(check(mid + 1, n - mid)) r = mid;
		else l = mid + 1;
	}

	std::cout << l << "\n";
}

int main() {
	int _;
	std::cin >> _;
	while(_ --) {
		solve();
	}
}
posted on 2023-01-29 17:21  Jack404  阅读(135)  评论(0)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3