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;
}
相关推荐
Forever Nore1 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考2 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX3 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面4 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号4 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽4 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI4 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
C++ 老炮儿的技术栈5 小时前
从 Qt Designer 属性编辑器的层级可以看到继承链
c语言·数据库·c++·qt·sqlite·visual studio
new_zhou6 小时前
C++ 项目 AI 协作指南(Windows / MSVC 环境)
c++·人工智能·windows
地平线开发者6 小时前
征程6工具链模型X86推理方式说明
算法