首页 > 其他分享 >询问(构造,一种新思路)

询问(构造,一种新思路)

时间:2024-08-15 20:29:36浏览次数:5  
标签:val min int 询问 新思路 构造 len Yes

第5题     询问 查看测评数据信息

给一个长度为n的正整数数组a[1,2,...n],一个长度为m的查询数组q[1,2,...m],q[i]=(val,minlen,maxlen)。请你按输入顺序处理这m次查询,对于第i次查询q[i[=(val,minlen,maxlen);请你输出是否存在一个a的子数组s满足min(s)≥val且s的长度在minlen和maxlen之间。

输入格式

 

第一行输入一个正整数n

第二行有n个正整数,a[1,2,...n]

第三行输入一个正整数m

接下来m行,每行三个正整数,表示q[i]的三个数,val,minlen,maxlen

1<=n,m<=1e5

1<=val,a[i]<=1e9

1<=minlen<=maxlen<=n

 

输出格式

 

输出m行,如果存在输出“Yes”,否则输出“No”

 

输入/输出例子1

输入:

3

1 3 2

6

1 1 3

1 1 2

3 2 2

3 1 2

4 1 1

2 1 2

 

输出:

Yes

Yes

No

Yes

No

Yes

 

样例解释

 

 

 

 

很有意思的一道压轴题。

对于正面无法很好回答的多次询问,我们可以自己构造答案,再对应询问给出构造答案

 

构造部分


 

首先可以发现,在一个区间中删去某些数,min肯定不会减小,所以maxlen没用,我们只需要minlen

比如{1,2,3,4}中的min是1,我们删去{3,4},min还是1,删去{1,2},min是3,无论怎么样,min不会减小,但是可能会增加

 

对于每个a[i],我们都可以构造一个答案,假设构造的区间是[L, R],只要L~R区间内每个数都>=a[i],就可以满足构造条件,使得这个区间内的最小值是a[i]

我们构造的答案区间长度就可以确定下来。我们现在可以尝试用构造的这些答案去跟询问一一对应

所以我们构造的答案包含两个值,一个是答案区间长度(后续称为len);一个是a[i],也就是区间中的min值,我们假定这个构造的答案是 f[i]

 

构造部分就结束了,接下来我们考虑如何把构造出来的答案对应上询问

 

对应询问部分


 

我们对这些f[i]排个序,从小到大,按照min去排序,这样就对于后来询问所给出的val,我们就可以考虑去这些答案区间中二分查找min值

二分f[i].min>=val,如何看看是否满足题意,f[i].len>=minlen,即可

由于排序后,min是从小到大的,根据第一点小发现,我们可以对len搞一个长度的后缀最大值,这样才可以保证满足答案

为什么可以这样?题目只是要求min(s)≥val就行,那么比min大的数肯定也是可以满足要求的,但是比min大的数它的最终区间长度可能比min要大!

例如排完序后的f[i]是这样的:

f[1]={1, 3}

f[2]={2, 2}

f[3]={3, 3}

我们先在求val=2,minlen=3

但是我们二分查表发现f[2].min>=val,但是 f[2].len=2,是不满足的,会被误判是”No“

但是答案其实是”Yes“,因为 f[3].min>=val,也是满足题目要求”min(s)>=val,所以f[3]的长度对这个答案也是有影响的,所以我们要整一个后缀最大值

 

我们看看后缀最大值是否>=minlen,是的话就是"Yes",反之亦然
这里的时间复杂度是 O(logn),仅有一个二分而已

 

我们再考虑回去

如何减小构造的时间复杂度呢?暴力就是O(n^2)

我们可以不用一一枚举,用单调队列可以预处理(找第一个<a[i]的数,找极值就是单调队列嘛!),也就是 O(n)

 

这里给出O(n^2 log n)复杂度的做法

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;

struct node
{
	int min, len;
}b[N];
int n, a[N], m, val, Minlen, Maxlen; 
/*
int find(int L, int R, int x)
{
	for (int i=R; i>=L; i--)
		if (a[i]<a[x]) return i+1;
	return L;
}*/
bool cmp(node a, node b)
{
	return a.min<b.min;
}
int main()
{
	scanf("%d", &n);
	for (int i=1; i<=n; i++) scanf("%d", &a[i]);
	scanf("%d", &m);
	
	for (int i=1; i<=n; i++)
	{
		int sum=0;
	//	L=find(1, i, i), R=find(i+1, n, i);
		for (int j=i-1; j>=1; j--)
		{
			if (a[j]<a[i]) break;
			sum++;
		}
	//	if (i==2) printf("{%d}", sum);
		for (int j=i+1; j<=n; j++)
		{
			if (a[j]<a[i]) break;
			sum++;
		}
		
		b[i].min=a[i], b[i].len=sum+1;
	}
	sort(b+1, b+1+n, cmp);
	for (int i=n-1; i>=1; i--) b[i].len=max(b[i].len, b[i+1].len);
	/*
	printf("\n");
	for (int i=1; i<=n; i++) printf("%d %d\n", b[i].min, b[i].len);
	printf("\n");
	*/
	while (m--)
	{
		scanf("%d%d%d", &val, &Minlen, &Maxlen);
		
		int L=1, R=n, x=0;
		while (L<=R)
		{
			int mid=(L+R)>>1;
			if (b[mid].min>=val) x=mid, R=mid-1;
			else L=mid+1;
		}
		//printf("{%d}", x);
		if (b[x].min<val) printf("No\n");	
		else
		{
			if (b[x].len>=Minlen) printf("Yes\n");
			else printf("No\n");
		}
	}
	return 0;
}
/*
3
1 3 2
1
3 1 2


*/

  

 

 

标签:val,min,int,询问,新思路,构造,len,Yes
From: https://www.cnblogs.com/didiao233/p/18361757

相关文章

  • File构造方法,成员方法,判断功能,基本获取功能
    packagecom.shujia.day16.ketang;importjava.io.File;/*File:是所有文件或者文件夹的路径抽象表现形式,对文件进行操作每次都需要创建文件的对象构造方法:publicFile(Stringpathname)通过将给定的路径名字符串转换为抽象路径名来创建新......
  • Java 入门指南:构造器
    Java构造器在Java中,构造器(Constructor)是一种特殊的方法,用于创建和初始化对象。它与类名相同,没有返回类型(甚至不能写void),主要用于在对象创建时设置对象的初始状态。构造器在面向对象编程中起着至关重要的作用,它确保了每个对象在创建时都有一个有效的初始状态。在对象创建时......
  • 构造题练习笔记
    例一hdu7393:题意:​有\(n\)个人,每个人头上有个\(1...m\)之间中的某个数字,每个人都能看到其他所有人的数字,但是看不到自己的数字,求一种整体策略,使得至少\(\lfloor\dfrac{n}{m}\rfloor\)个人猜对自己头上的数字。​\(m\len\)解答:​如果直接在\([1,m]\)......
  • Map概述、构造方法、遍历
    packagecom.shujia.day15;importjava.util.HashMap;importjava.util.Map;/*Map:存储元素的特点是每一个元素是一个键值对{【name:"魏一民"】,【age:18】}Map集合的共同拥有的特点:1、Map集合中的元素,键是唯一的,不会在一个Map集合发现两个相同的键......
  • [Lang] 构造与析构
    [Lang]构造和析构1.深拷贝与浅拷贝浅拷贝是在复制对象时,仅复制对象的成员变量的值,而不考虑这些成员变量是否指向了动态分配的内存或其他资源。也就是说,浅拷贝只复制指针的值,不复制指针所指向的内容。编译器默认提供的拷贝构造函数是浅拷贝。深拷贝是在复制对象时,不仅复制对......
  • 第18 章探讨 C++新标准 移动构造函数解析,强制移动
    第18章探讨C++新标准移动构造函数解析,强制移动第18章探讨C++新标准移动构造函数解析,强制移动文章目录第18章探讨C++新标准移动构造函数解析,强制移动18.2.5强制移动程序清单18.3stdmove.cpp18.2.5强制移动移动构造函数和移动赋值运算符使用右值。如果......
  • C++——构造函数和析构函数
    一、初识构造函数和析构函数简单来说,有对象生成必然会调用构造函数,有对象销毁必然会调用析构函数。构造函数的作用是初始化成员变量,是由编译器去调用的,而析构函数同理也是由编译器调用,不过他的作用则是清理。可以由下面的代码体验两个函数的使用。注意:相同点:两个函数都没有......
  • 构造用于线性回归分析使用的波动上升随机数据并绘制散点图
    一、简介进行线性数据回归分析经常需要用到波动上升的随机数据,本文给出了使用python构建的由线性数据+随机数据+正弦数据的波动上升数据并绘制散点图的代码和效果展示。该数据共5段100个可用于进行线性回归数据分析。二、代码#-*-coding:utf-8-*-#导入第三方库import......
  • JS中关于为什么调用构造函数要使用new的详细解读
    在JavaScript中,使用new关键字调用构造函数是创建新对象的关键步骤。本文将从以下几个方面解释为什么要这样做:1.创建一个新的对象当你用new调用构造函数时,会自动创建一个新的空对象,这个对象会被赋值给this,即构造函数内部的this关键字会引用这个新创建的对象。fu......
  • C++类和对象(中):构造函数、析构函数、拷贝构造、赋值运算符重载
    文章目录C++类和对象4、类的默认成员函数5、构造函数5.1构造函数的特点5.2实例分析6、析构函数6.1析构函数的特点6.2实例分析7、拷贝构造函数7.1拷贝构造函数的特点7.2实例分析7.3浅拷贝和深拷贝8、赋值运算符重载8.1运算符重载8.1.1运算符重载的特点8.1.2实例分析8.......