二分+RMQ/双端队列/尺取法 HDOJ 5289 Assignment
/*
题意:问有几个区间最大值-最小值 < k
解法1:枚举左端点,二分右端点,用RMQ(或树状数组)求区间最值,O(nlog(n))复杂度
解法2:用单调队列维护最值,O(n)复杂度,用法
解法3:尺取法,用mutiset维护最值
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std; typedef long long ll;
const int MAXN = 1e5 + ;
const int INF = 0x3f3f3f3f;
int a[MAXN];
int mn[MAXN][], mx[MAXN][]; //最多能保存524288的长度 int RMQ(int l, int r) {
int k = ; while (<<(k+) <= r - l + ) k++; //令k为满足1<<k <= r-l+1的最大整数
int MAX = max (mx[l][k], mx[r-(<<k)+][k]); //意思是区间最左边1<<k长度的最大值和最右边1<<k长度的最大值
int MIN = min (mn[l][k], mn[r-(<<k)+][k]); //可能有重叠的地方
return MAX - MIN;
} int main(void) { //HDOJ 5289 Assignment
freopen ("B.in", "r", stdin); int t; scanf ("%d", &t);
while (t--) {
int n, k; scanf ("%d%d", &n, &k);
for (int i=; i<=n; ++i) {
scanf ("%d", &a[i]);
mn[i][] = mx[i][] = a[i];
}
for (int j=; (<<j)<=n; ++j) {
for (int i=; i+(<<j)-<=n; ++i) {
mn[i][j] = min (mn[i][j-], mn[i+(<<(j-))][j-]); //mn[i][j]意思是从i开始,长度1<<j的区间的最小值
mx[i][j] = max (mx[i][j-], mx[i+(<<(j-))][j-]);
}
} ll ans = ;
for (int i=; i<=n; ++i) {
int l = i, r = n;
while (l + < r) { //二分使得l, r最远
int mid = (l + r) >> ;
if (RMQ (i, mid) < k) l = mid;
else r = mid;
}
if (RMQ (i, r) < k) { //此时[l, r](l+1==r) 其中一个一定满足条件
ans += (r - i + );
}
else {
ans += (l - i + );
}
}
printf ("%I64d\n", ans);
} return ;
}
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std; typedef long long ll;
const int MAXN = 1e5 + ;
const int INF = 0x3f3f3f3f;
int a[MAXN], n;
struct BIT {
int mn[MAXN], mx[MAXN]; void init(void) {
memset (mn, INF, sizeof (mn));
memset (mx, , sizeof (mx));
}
void add_min(int i, int x) {
while (i <= n) {
mn[i] = min (mn[i], x); i += i & (-i);
}
}
int query_min(int i) {
int res = INF;
while (i > ) {
res = min (res, mn[i]); i -= i & (-i);
}
return res;
}
void add_max(int i, int x) {
while (i <= n) {
mx[i] = max (mx[i], x); i += i & (-i);
}
}
int query_max(int i) {
int res = ;
while (i > ) {
res = max (res, mx[i]); i -= i & (-i);
}
return res;
}
}bit; int main(void) {
//freopen ("B.in", "r", stdin); int t; scanf ("%d", &t);
while (t--) {
int k; scanf ("%d%d", &n, &k);
for (int i=; i<=n; ++i) {
scanf ("%d", &a[i]);
} ll ans = ; bit.init ();
for (int i=n; i>=; --i) { //树状数组的特点,倒过来插入,求[i, n]区间
bit.add_min (i, a[i]);
bit.add_max (i, a[i]);
int l = i, r = n;
while (l <= r) {
int mid = (l + r) >> ;
int MAX = bit.query_max (mid);
int MIN = bit.query_min (mid);
if (MAX - MIN >= k) r = mid - ;
else l = mid + ;
}
ans += l - i;
}
printf ("%I64d\n", ans);
} return ;
}
树状数组
/*
维护递增和递减的队列,当队首满足条件时,添加个数,再在从后添加元素,否则pop_front
*/
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std; typedef long long ll;
const int MAXN = 1e5 + ;
const int INF = 0x3f3f3f3f;
struct Node {
int v, p;
};
int a[MAXN]; int main(void) {
//freopen ("B.in", "r", stdin); int t; scanf ("%d", &t);
while (t--) {
int n, k; scanf ("%d%d", &n, &k);
for (int i=; i<=n; ++i) scanf ("%d", &a[i]); deque<Node> Q1, Q2; ll ans = ; int head = ;
for (int i=; i<=n; ++i) {
Node now = (Node){a[i], i};
while (!Q1.empty ()) { //递减 队首max
Node tmp = Q1.back ();
if (now.v > tmp.v) Q1.pop_back ();
else break;
}
Q1.push_back (now);
while (!Q2.empty ()) { //递增 队首min
Node tmp = Q2.back ();
if (now.v < tmp.v) Q2.pop_back ();
else break;
}
Q2.push_back (now); if (i == ) ans++;
else {
while (true) {
Node big = Q1.front ();
Node small = Q2.front ();
if (big.v - small.v < k) break;
else {
if (small.p < big.p) {
head = small.p + ; Q2.pop_front ();
}
else {
head = big.p + ; Q1.pop_front ();
}
}
}
ans += i - head + ;
}
}
printf ("%I64d\n", ans);
} return ;
}
单调队列
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <set>
#include <cmath>
using namespace std; typedef long long ll;
const int MAXN = 1e5 + ;
const int INF = 0x3f3f3f3f;
multiset<int> S;
int a[MAXN]; int main(void) {
//freopen ("B.in", "r", stdin); int t; scanf ("%d", &t);
while (t--) {
int n, k; scanf ("%d%d", &n, &k);
for (int i=; i<=n; ++i) {
scanf ("%d", &a[i]);
} S.clear (); S.insert (a[]);
int l = , r = ; ll ans = ;
int mn, mx;
while (true) {
if (S.size ()) {
mn = *S.begin ();
mx = *S.rbegin ();
if (abs (a[r] - mn) < k && abs (a[r] - mx) < k) {
ans += S.size (); S.insert (a[r++]);
if (r > n) break;
}
else {
if (S.size ()) S.erase (S.find (a[l]));
l++;
}
}
else {
l = r; S.insert (a[r++]);
if (r > n) break;
}
} printf ("%I64d\n", ans + n);
} return ;
}
尺取法(multiset)
二分+RMQ/双端队列/尺取法 HDOJ 5289 Assignment的更多相关文章
- ACM-ICPC2018北京网络赛 80 Days(双端队列+尺取)
题目4 : 80 Days 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 80 Days is an interesting game based on Jules Ve ...
- POJ3662 SPFA//二分 + 双端队列最短路
https://cn.vjudge.net/problem/12427/origin 题意:求1到N第K + 1大条边权最小的路径 首先想到dp递推,dp[x][y]表示到x这个点经过y条免费边的最小 ...
- POJ 3662 Telephone Lines【二分答案+最短路】||【双端队列BFS】
<题目链接> 题目大意: 在一个节点标号为1~n的无向图中,求出一条1~n的路径,使得路径上的第K+1条边的边权最小. 解题分析:直接考虑情况比较多,所以我们采用二分答案,先二分枚举第K+ ...
- 双端队列(单调队列)poj2823 区间最小值(RMQ也可以)
Sliding Window Time Limit: 12000MS Memory Limit: 65536K Total Submissions: 41844 Accepted: 12384 ...
- 双端队列 HDOJ 3530 Subsequence
题目传送门 题意:问最长子序列,满足区间最大值 - 最小值在[m, k]之间 分析:用双端队列维护最大值和最小值,保存的是位置.当满足条件时,更新最大值. /********************* ...
- 洛谷P3222 [HNOI2012]射箭(计算几何,半平面交,双端队列)
洛谷题目传送门 设抛物线方程为\(y=ax^2+bx(a<0,b>0)\),我们想要求出一组\(a,b\)使得它尽可能满足更多的要求.这个显然可以二分答案. 如何check当前的\(mid ...
- lintcode二叉树的锯齿形层次遍历 (双端队列)
题目链接: http://www.lintcode.com/zh-cn/problem/binary-tree-zigzag-level-order-traversal/ 二叉树的锯齿形层次遍历 给出 ...
- lintcode 滑动窗口的最大值(双端队列)
题目链接:http://www.lintcode.com/zh-cn/problem/sliding-window-maximum/# 滑动窗口的最大值 给出一个可能包含重复的整数数组,和一个大小为 ...
- STL---deque(双端队列)
Deque是一种优化了的.对序列两端元素进行添加和删除操作的基本序列容器.它允许较为快速地随机访问,但它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个映射结 ...
随机推荐
- msp430入门编程05
msp430中C语言的运算符和表达式 msp430中C语言的程序结构06 msp430中C语言的函数及实现07 msp430中C语言操作端口I/O10 msp430中C语言的模块化头文件及实现11 m ...
- msp430入门学习00
在TI官网上找到MSP430的程序例程.数据手册.使用指南等文件.以MSP430F169为例,步骤如下: 1)进入ti官网:http://www.ti.com.cn/ 或者http://www.ti. ...
- Thinkphp5.0 的实践一
Thinkphp5.0 的实践一 tp5.0默认没有__SELF__,需要定义, define('__SELF__',strip_tags($_SERVER['REQUEST_URI'])); tp5 ...
- BitMap算法 .net实现 用于去重并且排序,适用于大型权限管理 ,大数据去重排序
BitMap利用byte特性 针对排序+去重 最佳实践: 100万条数据的排序+去重用时200毫秒左右 static void Main(string[] args) { ]; /*alias*/ ...
- eclipse断点有个斜杠 skip all breakpoints
切换到debug,单击下 skip all breakpoints 即可
- 牛腩新闻系统(一)——UML、数据库设计
牛腩新闻系统(一)--UML.数据库设计 一.初识牛腩系统 牛腩(Brisket)即牛腹部及靠近牛肋处的松软肌肉,是指带有筋.肉.油花的肉 块.这是一种统称. 若依部位来分,牛身上很多地方的肉都能够叫 ...
- golang 查询数据库操作
SQL.Open only creates the DB object, but dies not open any connections to the database. If you want ...
- ATM取款机模拟——数据结构课设
今天帮人写的第二篇课设 . ;-) 机智的窝 要求:大概说一下吧,就是要创建一个用户(初始化一账户),模拟ATM的业务(取款,100的整数倍,改密 码,查剩余金额.等等,各 ...
- Java总结之网络
[网络基础概念] 什么是计算机网络: 把分布在不同地理区域的计算机与专门的外部设备用通信线路互连成一个规模大.功能强的网络系统,从而使众多的计算机能够方便的互相传递信息,共享硬件.软件.数据信息等资源 ...
- JDBC基本应用
首先我们来看一下JDBC操作数据的核心: Connection 应用程序与数据库之间的桥梁 数据库驱动程序是构建桥梁的基石和材料 DriverManager类是基石和材料的管理员 Statement ...