我用递归写单调栈(?)

news/2024/7/15 17:28:12 标签: 算法, c++, 图论

在这里插入图片描述
前言:嗯,这个题上午有的思路,敲了一中午代码,改了一下午最后超时?
:D. Boris and His Amazing Haircut
题意:一个理发师可以把一段数组给建成一个高度,他现在每个高度的剪子都有若干个。给一个原始数组和目标数组,问能不能剪成目标数组。
奇怪的想法: 理发师最优的剪法就是先剪出来高的,然后在高的头发形成的段之间再剪次高的。直接上分治,结果超时,边界控制太难写了,
超时的代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
const int length = 2e5 + 5;
vector<int> ag;
vector<int> bg;
map<int,int> mp;
vector<int> count1;
vector<vector<int>> index1;
int tree[length << 3];
void update(int l, int r, int L, int R, int cnt, int v)
{
	if (L >= l && R <= r)
	{
		tree[cnt] = v;
		return;
	}
	if (L > r || R < l)
	{
		return;
	}
	int mid = (L + R) / 2;
	update(l, r, L, mid, cnt << 1, v);
	update(l, r, mid + 1, R, cnt * 2 + 1, v);
	tree[cnt] = max(tree[cnt * 2], tree[cnt * 2 + 1]);
}
int query(int l, int r, int L, int R, int cnt)
{
	if (L>=l&&R<=r)
	{
		return tree[cnt];
	}
	if (L > r || R < l)
		return 0;
	int mid = (L + R) / 2;
	int a = query(l, r, L, mid, cnt * 2);
	int b = query(l, r, mid + 1, R, cnt * 2 + 1);
	return max(a, b);
}
int n1;
bool DP(int l, int r)
{
	//if()
	if (l > r)
		return 1;
	int yh = query(l, r, 0, n1 - 1, 1);
	bool sum = 1;
	int lflag = ((l==0)?0:1);
	int rflag = ((r==n1-1)?0:-1);
	int cut = 0;
	//找到第一个大于等于l的数
	int a = -1;
	int b = index1[yh].size();
	while (a != b - 1)
	{
		int mid = (a + b) / 2;
		if (index1[yh][mid] < l)
			a = mid;
		else
			b = mid;
	}
	int i = b;
	int in = 0;
	for (; i<index1[yh].size()&&index1[yh][i]<=r; i++)
	{
		if (i != index1[yh].size() && mp[ag[index1[yh][i]]] != mp[bg[index1[yh][i]]]&&cut==0)
		{
			cut = 1;
			if (count1[mp[bg[index1[yh][i]]]])
				count1[mp[bg[index1[yh][i]]]]--;
			else
				return 0;
		}
		if (in == 0)
		{
			bool a=DP(l , index1[yh][i] - 1);
			sum = sum & a;
		}
		else
		{
			bool a = DP(index1[yh][i - 1] + 1, index1[yh][i] - 1);
			sum = sum & a;
		}
		if (sum == 0)
			return sum;
		in = 1;
	}
	if (i!=index1[yh].size()&&index1[yh][i] > r)
	{
		if (i != 0)
		{
			bool a = DP(index1[yh][i - 1] + 1, r);
			sum = sum & a;
		}
	}
	else if (i == index1[yh].size() && index1[yh][i - 1] != r)
	{
		bool a = DP(index1[yh][i - 1] + 1, r);
		sum = sum & a;
	}
	return sum;
}
int main(void)
{
	int t;
	scanf_s("%d", &t);
	for (int i = 0; i < t; i++)
	{
		int n;
		scanf_s("%d", &n);
		n1 = n;
		vector<int> a(n,0);
		for (int i = 0; i < n; i++)
		{
			scanf_s("%d", &a[i]);
		}
		vector<int> b(n, 0);
		for (int i = 0; i < n; i++)
		{
			scanf_s("%d", &b[i]);
		}
		int m;
		scanf_s("%d", &m);
		vector<int> c(m, 0);
		for (int i = 0; i < m; i++)
		{
			scanf_s("%d", &c[i]);
		}
		ag = a; bg = b;//全局变量赋值
		vector<int> tmp=b;
		sort(tmp.begin(), tmp.end());
		vector<int>::iterator p = unique(tmp.begin(), tmp.end());
		int off = p - tmp.begin();
		map<int, int> hk;
		int cnt = 1;
		for (int i = 0; i < off; i++)
		{
			hk[tmp[i]] = i + 1;
		}
		mp = hk;
		vector<int> tmp_count(length);
		for (int i = 0; i < m; i++)
		{
			tmp_count[mp[c[i]]]++;//统计映射之后的数量
		}
		count1 = tmp_count;
		memset(tree, 0, sizeof(tree));
		vector<vector<int>> edge(length);
		int ok = 1;
		for (int i = 0; i < n; i++)
		{
			if (a[i] < b[i])
				ok = 0;
			update(i, i, 0, n - 1, 1, mp[b[i]]);//更新区间最值以及坐标位置
			edge[mp[b[i]]].push_back(i);
		}
		if (ok == 0)
		{
			printf("NO\n");
			continue;
		}
		index1 = edge;
		int yh=DP(0, n - 1);
		if (yh)
			printf("YES\n");
		else
			printf("NO\n");
	}
}

正解
思考源头:为啥要剪一段?省剪子啊,他的剪子都是一次性的,用完不能再用乐。并且剪成高度为 5 5 5的时候不能穿过高度为 8 8 8的。所以就用单调栈呗,注意 a [ i ] = = b [ i ] a[i]==b[i] a[i]==b[i]的头发可以弹出数,但是不能入栈,入栈的目的就是不让两边相同高度的头发剪两次。但是 a [ i ] = = b [ i ] a[i]==b[i] a[i]==b[i]的可以作为山丘的两端,高度低的不能穿过他。
A C AC AC代码

#include<iostream>
#include<cstdio>
#include<map>
#include<stack>
using namespace std;
const int length = 2e5 + 5;
int a[length];
int b[length];
map<int, int> mp;
int main(void)
{
	int t;
	scanf_s("%d", &t);
	for (int i = 0; i < t; i++)
	{
		mp.clear();
		int n;
		scanf_s("%d", &n);
		for (int i = 0; i < n; i++)
		{
			scanf_s("%d", &a[i]);
		}
		for (int i = 0; i < n; i++)
		{
			scanf_s("%d", &b[i]);
		}
		int m;
		scanf_s("%d", &m);
		for (int i = 0; i < m; i++)
		{
			int a;
			scanf_s("%d", &a);
			mp[a]++;
		}
		int flag = 1;
		stack<int> s;
		for (int i = 0; i < n; i++)
		{
			if (a[i] < b[i])
			{
				flag = 0;
				break;
			}
			while (!s.empty() && s.top() < b[i])
				s.pop();
			if ((s.empty() || s.top() > b[i])&&a[i]!=b[i])
			{
				s.push(b[i]);
				if (mp[b[i]] == 0)
				{
					flag = 0;
					break;
				}
				mp[b[i]]--;
				
			}
		}
		if (flag == 0)
		{
			printf("NO\n");
		}
		else
			printf("YES\n");
	}
}

还有就是这个题的数值太大了,本来想用离散化的,但是如果能用 m a p map map的话直接用 m a p map map吧, n n n是够的。


http://www.niftyadmin.cn/n/27884.html

相关文章

什么是pod(容器组)

pod&#xff08;容器组&#xff09; 术语中英文对照&#xff1a; 英文全称英文缩写中文翻译PodPod容器组ContainerContainer容器ControllerController控制器 什么是 Pod 容器组&#xff1f; Pod&#xff08;容器组&#xff09;是 Kubernetes 中最小的可部署单元。一个 Pod&a…

LeetCode-1814. 统计一个数组中好对子的数目【哈希表】

LeetCode-1814. 统计一个数组中好对子的数目【哈希表】题目描述&#xff1a;解题思路一&#xff1a;由题中nums[i]rev(nums[j])nums[j]rev(nums[i])得到nums[i]-rev(nums[i])nums[j]-rev(nums[j])解题思路二&#xff1a;0解题思路三&#xff1a;0题目描述&#xff1a; 给你一个…

[Leetcode] 股票的价格跨度(单调栈)

题目链接&#xff1a;496 下一个更大元素 I901 股票价格跨度先看一道单调栈相关的题目下一个更大元素nums1 中数字 x 的 下一个更大元素 是指 x 在 nums2 中对应位置右侧的 第一个 比 x 大的元素。两个没有重复元素的数组 nums1 和 nums2 &#xff0c;下标从 0 开始计数&#x…

人工智能所需高等数学知识大全(收藏版)

来源&#xff1a;投稿 作者&#xff1a;愤怒的可乐 编辑&#xff1a;学姐 不懂数学是学不好人工智能的&#xff0c;本系列文章就汇总了人工智能所需的数学知识。本文是高等数学篇。 另有线代篇和概率论篇 函数与极限 函数 yf(x) ,x是函数f的自变量&#xff0c;y是因变量 函…

文件上传oss,并查询上传进度(SpringBoot+Redis+Oss+Swagger3)

文章目录诉求技术选型pom配置项目结构文件树图示结构代码实现配置相关配置文件yamlSwagger3配置跨域问题配置oss相关ServiceControllerApplicationSwagger接口操作获取上传文件标识号获取文件上传进度小结诉求 将文件上传到oss&#xff0c;并实时监听上传进度&#xff0c;并将进…

设计模式之装饰者模式

装饰者模式 定义 先上定义&#xff1a;指在不改变现有对象结构的情况下&#xff0c;动态地给该对象增加一些职责&#xff08;即增加其额外功能&#xff09;的模式。 优缺点 优点&#xff1a; 1&#xff0c;装饰器是继承的有力补充&#xff0c;比继承灵活&#xff0c;在不改…

蓝桥杯算法训练合集四 1.p0802 2.A的B的C次方次方 3.出现次数最多的整数 4.成绩分级 5.台阶问题

目录 1.p0802 2.A的B的C次方次方 3.出现次数最多的整数 4.成绩分级 5.台阶问题 1.p0802 问题描述 编写一个字符串表达式求解函数int expression(char* s); 输入一个字符串表达式&#xff0c;返回它的结果。表达式长度不会超过100。表达式最少有一项&#xff0c;且以等号…

子集和(Python)

子集和问题是回溯法的一个典型应用,本文主要用Python解决这个问题。 子集和问题 问题描述 【问题描述】子集和问题的一个实例为〈S,c〉。其中,S={ x1 , x2 ,…,xn }是一个正整数的集合,c是一个正整数。子集和问题判定是否存在S的一个子集S1,使得: 试设计一个解子集和问…