二分+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 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个映射结 ...
随机推荐
- CF601D:Acyclic Organic Compounds
给n<=300000的树,每个点上有一个字母,一个点的权值为:从该点出发向下走到任意节点停下形成的不同字符串的数量,问最大权值. 题目本身还有一些奇怪要求在此忽略.. Trie合并的模板题. # ...
- hdu - 1394 Minimum Inversion Number(线段树水题)
http://acm.hdu.edu.cn/showproblem.php?pid=1394 很基础的线段树. 先查询在更新,如果后面的数比前面的数小肯定会查询到前面已经更新过的值,这时候返回的sum ...
- ZOJ 1298_Domino Effect
题意: 多米诺骨牌效应:若干个关键牌相连,关键牌之间含有普通牌,关键牌倒下后其所在的行的普通牌全部倒下.求从推倒1号关键牌开始,最终倒下的牌的位置及时间. 分析: 最终倒下的牌的位置有两种情况,要么是 ...
- Eclipse的SVN插件 Subclipse
原文:https://www.oschina.net/p/subclipse Subclipse 是一个为 Eclipse IDE 添加 Subversion 支持的项目.支持几乎所有版本的Eclip ...
- java读取大文本文件
原文:http://blog.csdn.net/k21325/article/details/53886160 小文件当然可以直接读取所有,然后放到内存中,但是当文件很大的时候,这个方法就行不通了,内 ...
- commons-lang常用工具类StringEscapeUtils
原文:https://my.oschina.net/mousai/blog/88832 在apache commons-lang(2.3以上版本)中为我们提供了一个方便做转义的工具类,主要是为了防止s ...
- 模拟用户点击弹出新页面不会被浏览器拦截_javascript技巧
原文:http://www.html5cn.com.cn/article/zxzx/3195.html 相信用过window.open的小伙伴们都遇到过被浏览器拦截导致页面无法弹出的情况:我们换下思路 ...
- IOS程序崩溃报告管理解决方案(Crashlytics 在2014-09-24)
预研Crashlytics 在2014-09-241:实现原理在原理上,Crashlytics通过以下2步完成崩溃日志的上传和分析:(1)提供应用SDK,你需要在应用启动时调用其SDK来设置你的应用 ...
- 混合式框架-AgileLite
Agile Lite是一个HTML5移动前端框架.支持jQuery和Zepto双引擎.而且提供与UI无关的独立框架,内置了Flat UI样式和Ratchet样式.同一时候也支持单页模式和多页模式开发. ...
- C/C++生成可执行文件过程
编译的概念:编译程序读取源程序(字符流),对之进行词法和语法的分析,将高级语言指令转换为功能等效的汇编代码,再由汇编程序转换为机器语言,并且按照操作系统对可执行文件格式的要求链接生成可执行程序.编译的 ...