hdu5289(Assignment)
Description
Input
Output
Sample Input
Sample Output
题意:给定一个正整数序列,问有多少个连续子序列,其中最大值与最小值之差小于k?
题解:神奇的单调队列,用一个单调递增和一个单调递减队列来维护最小值与最大值,用两个前后指针,前指针指向当前区间左端点,后指针指向当前元素。如果当前加入新元素之后,max-min>=k,那么与新元素相差至少k的那个元素之前的所有元素都将失效,也就是出队。每一次操作答案都加上新元素向左可以延伸的最大距离。
例子:n=6,k=3,序列为5 3 5 2 3 4。q1为单调增队列,q2为单调减队列。
step1 :
q1 : 5
q2 : 5
l = 0, r = 0
ans = 1
step2 :
q1 : 3
q2 : 5 3
l = 0, r = 1
ans = 1 + 2
step3 :
q1 : 3 5
q2 : 5
l = 0, r = 2
ans = 1 + 2 + 3
step4 :
q1 : 2
q2 : 5 2
l = 0, r = 3
这时候发现q1中最小值与q2中最大值差值3>=k,那么开始出队。
q1 : 2
q2 : 2
l = 3, r = 3
ans = 1 + 2 + 3 + 1
step5 :
q1 : 2 3
q2 : 3
l = 3, r = 4
ans = 1 + 2 + 3 + 1 + 2
step6 :
q1 : 2 3 4
q2 : 4
l = 3, r = 5
ans = 1 + 2 + 3 + 1 + 2 + 3
所以最后答案为12
#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <map>
#include <vector>
#include <list>
#include <set>
#include <stack>
#include <queue>
#include <deque>
#include <algorithm>
#include <functional>
#include <iomanip>
#include <limits>
#include <new>
#include <utility>
#include <iterator>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <ctime>
using namespace std;
int a[100010];
deque<int> q1, q2;
int main()
{
int T;
cin >> T;
while (T--)
{
int n, k;
cin >> n >> k;
for (int i = 0; i < n; ++i)
scanf("%d", &a[i]);
q1.clear();
q2.clear();
int l = 0, r = 0;
long long ans = 0;
while (r < n)
{
while (!q1.empty() && q1.back() > a[r])
q1.pop_back();
q1.push_back(a[r]);
while (!q2.empty() && q2.back() < a[r])
q2.pop_back();
q2.push_back(a[r]);
while (!q1.empty() && !q2.empty() && q2.front() - q1.front() >= k)
{
if (q1.front() == a[l])
q1.pop_front();
if (q2.front() == a[l])
q2.pop_front();
l++;
}
ans += r - l + 1;
r++;
}
cout << ans << endl;
}
return 0;
}
posted on 2020-01-17 01:03 godweiyang 阅读(55) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步