2015多校联合训练第一场Assignment(hdu5289)三种解法

2024-09-07 18:32

本文主要是介绍2015多校联合训练第一场Assignment(hdu5289)三种解法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目大意:给出一个数列,问其中存在多少连续子序列,子序列的最大值-最小值< k
这题有三种解法:
1:单调队列,时间复杂度O(n)
2:RMQ+二分,时间复杂度O(nlogn)
3:RMQ+贪心,时间复杂度O(nlogn)

一:RMQ+二分
RMQ维护最大值,最小值,枚举左端点i,二分找出最远的符合的右端点j,答案就是ans += j - i+1;(手推一下就知道)
比如1 2 3
含有i的有三种
1
1 2
1 2 3
其它的2,2 3,3下面i=2的时候会算的,所以每次加j-i+1就行

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
using namespace std;int  maxsum[100000][30];
int minsum[100000][30];int a[100000];
int n,k;
void rmq_init()
{for(int j = 1; (1<<j) <= n; ++j)for(int i = 1; i + (1<<j) - 1 <= n; ++i){maxsum[i][j] = max(maxsum[i][j-1],maxsum[i+(1<<(j-1))][j-1]); minsum[i][j] = min(minsum[i][j-1],minsum[i+(1<<(j-1))][j-1]);}}int query(int l, int r)
{int k = log2(r-l+1);int Max = max(maxsum[l][k], maxsum[r-(1<<k)+1][k]);int Min = min(minsum[l][k], minsum[r-(1<<k)+1][k]);return Max - Min;
}int main()
{int T;scanf("%d",&T);while(T--){scanf("%d%d",&n,&k);for(int i = 1; i <= n;++i){scanf("%d",a+i);maxsum[i][0] = minsum[i][0] = a[i];}rmq_init();long long  ans = 0;int l , r;for(int i = 1; i <= n; ++i){l = i , r = n;while(l <= r){int mid = (l+r)/2;int cha = query(i,mid);if(cha < k) l = mid+1;else r = mid - 1;}ans += l - i;}printf("%lld\n",ans);}return 0;
}

二:单调队列
用单调队列维护最大值最小值,双指针,第一个第二个指针初始指向第一个数据,第一个指针按顺序不断向队尾添加数据,当最大值最小值的差大于等于k后,就意味着新添加的这个不能作用于当前第二个指针的位置,也就能计算出,以第二个指针位置开始的连续子序列的个数,最后统计总和。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std ;
#define LL long long
deque <LL> Max , Min ;
//单调队列,Max最大值,Min最小值
LL a[100010] ;
int main()
{int T , n , i , j ;LL k , ans ;scanf("%d", &T) ;while( T-- ){scanf("%d %I64d", &n, &k) ;for(i = 0 ; i < n ; i++)scanf("%I64d", &a[i]) ;while( !Max.empty() ) Max.pop_back() ;while( !Min.empty() ) Min.pop_back() ;for(i = 0 , j = 0 , ans = 0; i < n ; i++)  //i在前,j在后{while( !Max.empty() && Max.back() < a[i] ) Max.pop_back() ;Max.push_back(a[i]) ;while( !Min.empty() && Min.back() > a[i] ) Min.pop_back() ;Min.push_back(a[i]) ;while( !Max.empty() && !Min.empty() && Max.front() - Min.front() >= k ){ans += (i-j) ;if( Max.front() == a[j] ) Max.pop_front() ;if( Min.front() == a[j] ) Min.pop_front() ;j++ ;}}while( j < n ){ans += (i-j) ;j++ ;}printf("%lld\n", ans) ;}return 0 ;
}

三:RMQ+贪心
这种枚举右端点,贪心选取右端点(类似尺取法)

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cmath>
using namespace std;int  maxsum[100000][30];
int minsum[100000][30];int a[100000];
int n,m;
void rmq_init()
{for(int j = 1; (1<<j) <= n; ++j)for(int i = 1; i + (1<<j) - 1 <= n; ++i){maxsum[i][j] = max(maxsum[i][j-1],maxsum[i+(1<<(j-1))][j-1]);minsum[i][j] = min(minsum[i][j-1],minsum[i+(1<<(j-1))][j-1]);}}int query(int l, int r)
{int k = log2(r-l+1);int Max = max(maxsum[l][k], maxsum[r-(1<<k)+1][k]);int Min = min(minsum[l][k], minsum[r-(1<<k)+1][k]);return Max - Min;
}int main()
{int T;scanf("%d",&T);while(T--){scanf("%d%d",&n,&m);for(int i = 1; i <= n; ++i){scanf("%d",a+i);maxsum[i][0] = minsum[i][0] = a[i];}rmq_init();long long  ans = 0;int k=1;for(int i=1; i<=n; i++){while(query(k,i)>=m&&k<i)k++;ans+=(i-k+1);}printf("%lld\n",ans);}return 0;
}

下面分别是三种算法运行时间(3,2,1)
可见时间效率单调队列最好(405ms),贪心+rmq(733ms)次之,二分+rmq(1216ms)最差
这里写图片描述

这篇关于2015多校联合训练第一场Assignment(hdu5289)三种解法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1145824

相关文章

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

详解Java中三种状态机实现方式来优雅消灭 if-else 嵌套

《详解Java中三种状态机实现方式来优雅消灭if-else嵌套》这篇文章主要为大家详细介绍了Java中三种状态机实现方式从而优雅消灭if-else嵌套,文中的示例代码讲解详细,感兴趣的小伙伴可以跟... 目录1. 前言2. 复现传统if-else实现的业务场景问题3. 用状态机模式改造3.1 定义状态接口3

redis中session会话共享的三种方案

《redis中session会话共享的三种方案》本文探讨了分布式系统中Session共享的三种解决方案,包括粘性会话、Session复制以及基于Redis的集中存储,具有一定的参考价值,感兴趣的可以了... 目录三种解决方案粘性会话(Sticky Sessions)Session复制Redis统一存储Spr

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

Python清空Word段落样式的三种方法

《Python清空Word段落样式的三种方法》:本文主要介绍如何用python-docx库清空Word段落样式,提供三种方法:设置为Normal样式、清除直接格式、创建新Normal样式,注意需重... 目录方法一:直接设置段落样式为"Normal"方法二:清除所有直接格式设置方法三:创建新的Normal样

把Python列表中的元素移动到开头的三种方法

《把Python列表中的元素移动到开头的三种方法》在Python编程中,我们经常需要对列表(list)进行操作,有时,我们希望将列表中的某个元素移动到最前面,使其成为第一项,本文给大家介绍了把Pyth... 目录一、查找删除插入法1. 找到元素的索引2. 移除元素3. 插入到列表开头二、使用列表切片(Lis

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN

Java继承映射的三种使用方法示例

《Java继承映射的三种使用方法示例》继承在Java中扮演着重要的角色,它允许我们创建一个类(子类),该类继承另一个类(父类)的所有属性和方法,:本文主要介绍Java继承映射的三种使用方法示例,需... 目录前言一、单表继承(Single Table Inheritance)1-1、原理1-2、使用方法1-

Java调用C#动态库的三种方法详解

《Java调用C#动态库的三种方法详解》在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们... 目录方法1:C++/CLI搭建桥梁——Java ↔ C# 的“翻译官”步骤1:创建C#类库(.NET