Codeforces Round 1052 (Div. 2) C. Wrong Binary Searchong Binary Search

题目意思:

给一个二进制字符串,字符串下标从1开始,如果si为1则i为稳定点,反正为不稳定点,需要我们依据伪代码构造一个长度为n的排序,使得排序中的每个数都满足对应s中的稳定点与不稳定点。

思路:

伪代码二分原理:

fun(x)

m为区间l,r上一个点

如果 pm==x,返回m

否则:

如果区间右端点的值大于pm,r=m-1

否则 l=m+1

简单地说:

伪代码只会判断pm是否大于x!!!

伪代码只会判断pm是否大于x!!!

伪代码只会判断pm是否大于x!!!

若大于x就缩短右边界

反正缩短做左边界

而对于稳定点:

当且仅当find(x)==x时,x才为稳定点,也就是px=x

若find(x)!=x,或未定义,那么x都是不稳定点,也就是px!=x

要使得i点为稳定点,首先必须保证pi=i;

之后就要让伪代码能搜到结点i

因为伪代码任取一点m,只会判断pm是否大于x,如果比i大就收缩右端点

如果比i小就收缩左端点

因此只要i在区间l,r上就必须保证l,i-1上的数都小于i,i+1,r上的数都大于i

这样就可以使得无论在区间上取到哪个数,无论怎么收缩,i都包含在收缩后的边界内,直至搜到i

然而在所有的稳定点必然是按照从小到大排列的基础上:

1.相邻稳定点之间:如果有非稳定点,则非稳定点个数一定>=2,即2相邻稳定点之间距离=2时无效

证:

如果非稳定点个数=1,举例:s=101的情况下,1为稳定点,2为不稳定点,3为稳定点

在p1=1,p3=3的基础上,p2只能为2

那么p=123,结点2就成了稳定点,与s=101不符

如果非稳定点个数>=2,如非稳定点个数=2,举例:s=1001,1为稳定点,2为不稳定点,3为不稳定点 4为稳定点

下标区间2,3只要做到比1大,比4小即可,那么 p=1324 同样可以保证 1,4稳定,2,3不稳定

因为伪代码任取一点m,只会判断pm是否大于x,

区间上除1之外的所有点都是比1大的,所以在搜索1时只会不断收缩右边界,直至搜到1

区间上除4之外的所有点都是比4大的,所以在搜索4时只会不断收缩左边界,直至搜到4

非稳定点个数>2时同理

2.最小稳定点之前:如果有非稳定点,则非稳定点个数一定>=2,即第一个稳定点为2时无效

如果非稳定点个数=1,举例:s=011的情况下,1为不稳定点,2为稳定点,3为稳定点

p1的位置只能是1,此时i就成了稳定点,与s不符

如果非稳定点个数>=2,如非稳定点个数=2,举例:s=0011,1为不稳定点,2为不稳定点,3为稳定点 4为稳定点

p可以为1234,也可以为2134;当p=2134时,因为所有数都比3,4小所以会不断收缩左边界

非稳定点个数>2时同理

3.最大稳定点之后:如果有非稳定点,则非稳定点个数一定>=2,即最后一个稳定点为n-1时无效

证明过程同2.

在上述推导过程中不难看出,在构造排序时,可以利用稳定点将整个排序拆分成若干子区间

在子区间上逆序构造排序即可

AC代码:

cpp 复制代码
#include<iostream>
#include<vector>
using namespace std;
vector<int> a;//存储所有稳定点
vector<int> p;
void build(int l, int r) {//构造函数
	int len = r - l + 1;
	if (len % 2 == 0) {
		for (int i = r;i >= l;i--) {
			p.push_back(i);
		}
	}
	else {
		int k = (r + l) / 2;
		for (int i = r;i >= l;i--) {
			if (i != k) {
				p.push_back(i);
			}
		}
		p.push_back(k);
	}
}
int main() {
	int t;
	cin >> t;
	getchar();
	while (t--) {
		a.clear();
		p.clear();
		int n;
		cin >> n;
		getchar();
		string s;
		cin >> s;
		a.push_back(0);
		for (int i = 0;i < n;i++) {
			if (s[i] == '1') {
				a.push_back(i + 1);
			}
		}
		if (a.size() == 1) {//没有稳定点
			cout << "YES" << endl;
			for (int i = n;i >= 1;i--) {
				cout << i << " ";
			}
			cout << endl;
		}
		else if (a.size() == n + 1) {//所有点都是稳定点
			cout << "YES" << endl;
			for (int i = 1;i <= n;i++) {
				cout << i << " ";
			}
			cout << endl;
		}
		else {
			bool flag = 1;
			int ll = a[1];//第一个稳定点
			int rr = a.back();//最后一个稳定点
			if (ll == 2 || rr == n - 1) {
				cout << "NO" << endl;
				continue;
			}
			for (int i = 1;i < a.size();i++) {
				if (a[i] - a[i - 1] == 2) {//稳定点之间距离=2且不为0
					flag = 0;
					break;
				}
			}

			if (!flag) {
				cout << "NO" << endl;
			}
			else {	
				cout << "YES" << endl;
				//  构造排序
				for (int i = 1;i < a.size();i++) {
					int l = a[i - 1] + 1;
					int r = a[i] - 1;
					if (l < r) {
						build(l, r);
					}
					p.push_back(a[i]);
				}

				if (a.back() < n) {//处理末尾
					int l = a.back() + 1;
					int r = n;
					build(l, r);
				}
				for (int i : p) {
					cout << i << " ";
				}
				cout << endl;
			}
		}
	}
	return 0;
}
相关推荐
fpcc4 小时前
c++编程实践—堆和栈越界调试
c++
yi0114 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
weiabc5 小时前
MSYS2 UCRT64 + g++ C++ 中文输出乱码 完整全过程
c++
Escalating_xu6 小时前
【C 语言】数据在内存中的存储:补码、大小端、整型陷阱与 IEEE 754 全解析
java·c语言·网络
灯澜忆梦7 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下7 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
Evand J7 小时前
【电机滤波例程5】渐消因子自适应扩展卡尔曼滤波(EKF),MATLAB。PMSM负载突变下的状态估计。附下载链接
算法·matlab
H.莓飛7 小时前
【数据结构】二叉树_OJ题
linux·开发语言·数据结构·算法
好想像大佬一样能够ak所有8 小时前
Leetcode35.搜索插入位置
数据结构·算法·leetcode
aqiu1111118 小时前
【C++算法打怪专栏】LeetCode 165. 比较版本号(双指针与字符串流法)
c++·算法·leetcode