题意:给出一个数列。问当中存在多少连续子区间,当中子区间的(最大值-最小值)<k

思路:设dp[i]为从区间1到i满足题意条件的解。终于解即为dp[n]。

此外 如果对于arr[i] 往左遍历 一直到arr[r] 此时从区间r到区间i满足(最大值-最小值)<k,再往左一位即越界 或者 不满足条件,此时有 dp[i]
= dp[i-1]
+ i - r
+ 1;

由于数据量大 往左遍历时 可能会超时 ,所以用rmq打表 查找r时用二分 就过了

代码:

#include <algorithm>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <cstring>
#include <iomanip>
#include <cstdio>
#include <string>
#include <bitset>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <map>
#include <set>
#define sss(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define mem1(a) memset(a,-1,sizeof(a))
#define mem(a) memset(a,0,sizeof(a))
#define ss(a,b) scanf("%d%d",&a,&b)
#define s(a) scanf("%d",&a)
#define INF 0x3f3f3f3f
#define w(a) while(a)
#define PI acos(-1.0)
#define LL long long
#define eps 10E-9
#define N 100010
using namespace std;
void mys(int& res) {
int flag=0;
char ch;
while(!(((ch=getchar())>='0'&&ch<='9')||ch=='-'))
if(ch==EOF) res=INF;
if(ch=='-') flag=1;
else if(ch>='0'&&ch<='9') res=ch-'0';
while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0';
res=flag?-res:res;
}
void myp(int a) {
if(a>9)
myp(a/10);
putchar(a%10+'0');
}
/********************the end of template********************/
int arr[N];
int sm[N][30], bg[N][30];
LL dp[N];
void rmq_init(int n) {
for(int i = 0; i < n + 1; i++) bg[i][0] = sm[i][0] = arr[i];
for(int j = 1; (1 << j) <= n + 1; j++) {
for(int i = 0; i + (1 << j) - 1 < n + 1; i++) {
bg[i][j] = max(bg[i][j - 1], bg[i + (1 << (j - 1))][j - 1]);
sm[i][j] = min(sm[i][j - 1], sm[i + (1 << (j - 1))][j - 1]);
}
}
}
int rmq_min(int left, int right){
int kk = 0;
w((1 << (kk+1)) <= right - left +1) kk++;
return min(sm[left][kk], sm[right - (1<<kk) +1][kk]);
}
int rmq_max(int left, int right){
int kk = 0;
w((1 << (kk+1)) <= right - left +1) kk++;
return max(bg[left][kk], bg[right - (1<<kk) +1][kk]);
}
int getR(int L, int k, int R) {
int l = L, r = R, m, ans;
while(l <= r) {
m = (l + r) >> 1;
int view = rmq_max(m, R) - rmq_min(m, R);
if(view < k) {
ans = m;
r = m - 1;
}
else l = m + 1;
}
return ans;
}
int main(){
int t;
s(t);
w(t--){
int n, k;
mem(dp);
ss(n, k);
for(int i=1; i<=n; i++){
s(arr[i]);
}
rmq_init(n);
dp[1] = 1;
for(int i=2; i<=n; i++){
int R = getR(1, k, i);
dp[i] = dp[i-1] + i - R + 1;
}
cout<<dp[n]<<endl;
}
return 0;
}

最新文章

  1. C语言指针转换为intptr_t类型
  2. Interface小例子
  3. [转]C#操作注册表
  4. iOS边练边学--Http网络再学习,简单介绍
  5. hdu2072 字典树
  6. media type与media query
  7. 过滤3个字节以上的utf-8字符
  8. Filter介绍
  9. jQuery之防止冒泡事件
  10. angular这个大梗的学习笔记
  11. BIG5编码表
  12. Zimbra8.x邮件服务器安装及配置
  13. Delphi中methodaddress的汇编代码解析
  14. 【转】介绍几个图论和复杂网络的程序库 —— BGL,QuickGraph,igraph和NetworkX
  15. Win10下CISCO VPN Client无法安装解决方案
  16. 【Python3爬虫】拉勾网爬虫
  17. 简化实现动态行列转置的SQL
  18. 使用mongo shell转换字符类型
  19. JDBC编程之预编译SQL与防注入式攻击以及PreparedStatement的使用教程
  20. Webkit内核探究【2】——Webkit CSS实现

热门文章

  1. ansible示例,离线安装etcd
  2. iframe中跨域页面访问parent的方法
  3. git基本操作:上传代码
  4. java BlockingQueue 用法
  5. Hbase框架原理及相关的知识点理解、Hbase访问MapReduce、Hbase访问Java API、Hbase shell及Hbase性能优化总结
  6. 关于Unity中LOD和渲染队列----渲染通道通用指令(一)
  7. C++编程基础练习
  8. OpenGL中的二维编程——从简单的矩形开始
  9. Spring JDBC批量操作
  10. C# 根据第几周和季度 获取开始时间和结束时间