hdu5289 Assignment --2015多校训练赛(一)

2024-08-24 12:38

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

题意:

给定一串数字,里面存在多少个区间[l, r] 使得里面的最大值与最小值之差小于k。

思路:

用RMQ预处理出所有区间的最大值与最小值之差。之后枚举左端点L, 二分处理差值小于k的最左边端点R,把所有

的R-L+1加上就是答案。


/************************************************ Author: fisty* Created Time: 2015-08-20 22:09:44* File Name   : hdu5289.cpp*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define Memset(x, a) memset(x, a, sizeof(x))
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
#define FOR(i, a, b) for(int i = a;i < b; i++)
#define lson l, m, k<<1
#define rson m+1, r, k<<1|1
#define MAX_N 100100
int t;   
int n, k;
int a[MAX_N];
int mi[MAX_N][20], ma[MAX_N][20];void RMQ()
{for (int i = 0; i < n; ++i)mi[i][0] = ma[i][0] = a[i];for (int j = 1; (1<<j) <= n; ++j)for (int i = 0; i+(1<<j)-1 < n; ++i){mi[i][j] = min(mi[i][j-1], mi[i+(1<<(j-1))][j-1]);ma[i][j] = max(ma[i][j-1], ma[i+(1<<(j-1))][j-1]);}}int query(int lt, int rt)
{int k = 0;while ((1<<(k+1)) <= rt-lt+1)k++;return max(ma[lt][k], ma[rt-(1<<k)+1][k]) - min(mi[lt][k], mi[rt-(1<<k)+1][k]);
}
int Binary_Search(int x){int l = x, r = n-1;while(r - l > 1){int mid = (l + r) / 2;if(query(x, mid) < k) l = mid;else r = mid;}if(query(x, r) < k)return r;return l;
}
void solve(){LL ans = 0;int t;for(int i = 0;i < n; i++){t = Binary_Search(i);ans += t - i + 1;}printf("%lld\n", ans);
}
int main() {//freopen("in.cpp", "r", stdin);//cin.tie(0);//ios::sync_with_stdio(false);scanf("%d", &t);while(t--){scanf("%d%d", &n, &k);for(int i = 0;i < n; i++){scanf("%d", &a[i]);}RMQ();solve();}return 0;
}

2.线段树:

首先,以a[n]起始的区间肯定是[n, n]。

然后以a[n-1]起始的区间最长是[n-1, n],然后考虑需不需要把区间的右值减小,也就是考虑a[n]和a[n-1]的差值是否小于k。假设最终的区间为[n-1, d(n-1)]。

于是对于以a[n-2]起始的区间,自然最长是[n-2, d(n-1)],然后考虑需不需要把区间的右值减小,也就是考虑这个区间内是否存在某个值与a[n-2]的差值大于等于k。

以此类推,以a[i]起始的区间应为[i, min(d(i+1), p)],其中p是i右侧最后一个满足与a[i]差值小于k的数的脚标。

采用线段树记录区间的最大值和最小值,就能查询出任意[i, n]区间里第一个满足与a[i]差值大于等于k的值的位置x,然后x-1即为最后一个满足与a[i]差值小于k的数的脚标。

/************************************************ Author: fisty* Created Time: 2015-08-21 20:26:03* File Name   : hdu5289 (2).cpp*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define Memset(x, a) memset(x, a, sizeof(x))
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
#define FOR(i, a, b) for(int i = a;i < b; i++)
#define lson l, m, rt<<1
#define rson m+1, r, rt<<1|1
//线段树版 
//采用线段树记录区间的最大值和最小值,就能查询出任意[i, n]区间里第一个满足与
//Ai差值大于等于k的值的位置x,然后x-1即为最后一个满足与Ai差值小于k的数的脚标。
int n, k;
const int MAX_N = 110000;
int _max[MAX_N << 2];
int _min[MAX_N << 2];
int p = -1;
int a[MAX_N];
struct Tree{void pushup(int rt){_max[rt] = max(_max[rt<<1], _max[rt<<1|1]);_min[rt] = min(_min[rt<<1], _min[rt<<1|1]);}void build(int l, int r, int rt){_max[rt] = _min[rt] = 0;if(l == r){_min[rt] = _max[rt] = a[l];return ;}int m = (l + r) >> 1;build(lson);build(rson);pushup(rt);}void query(int a, int b, int v){query(a, b, 1, n, 1,  v);}void query(int a, int b, int l, int r, int rt, int v){if(l == r){if(abs(_min[rt] - v) >= k){if(p == -1 || p > l){p = l;}}return;}int m = (l + r) >> 1;if(a <= m){if(abs(_min[rt<<1] - v) >= k || abs(_max[rt<<1] - v) >= k){query(a, b, lson, v);}}if(p == -1 && b > m){if(abs(_min[rt<<1|1] - v) >= k || abs(_max[rt<<1|1] - v) >= k){query(a, b, rson, v);}}}
}segtree;int t;
void solve(){LL ans = 1;int d[MAX_N];d[n] = n;for(int i = n-1; i >= 1; i--){p = -1;segtree.query(i, n, a[i]);if(p == -1){p = n;}else{p--;}d[i] = min(d[i+1], p);ans += d[i] - i + 1;}   printf("%lld\n", ans);
}
int main() {//freopen("in.cpp", "r", stdin);//cin.tie(0);//ios::sync_with_stdio(false);scanf("%d", &t);while(t--){scanf("%d%d", &n, &k);for(int i = 1;i <= n; i++){scanf("%d", &a[i]);}segtree.build(1, n, 1);solve();}return 0;
}






这篇关于hdu5289 Assignment --2015多校训练赛(一)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

CF Bayan 2015 Contest Warm Up B.(dfs+暴力)

B. Strongly Connected City time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/475/probl

CF Bayan 2015 Contest Warm Up A.(模拟+预处理)

A. Bayan Bus time limit per test 2 seconds memory limit per test 256 megabytes input standard input output standard output 题目链接: http://codeforces.com/contest/475/problem/A The fi

2015年校赛总结

题目名为“校赛总结”,其实更想换成“Rainbow为什么五题滚粗?!”。作为今年校赛大二没拆的两个队伍之一,结果打成这样,没脸见人了,总结起来就是我认为自己今天SB了。主要有以下几点: 1.我今天状态的确不好,最后卡的那道B题跟去年在农大校赛上遇见的那题类似,在最后那段时间我已经有思路了,可是由于当时不敢写。等到最后15分钟才开始敲,加上我用很麻烦的Dijstra那种方法,调试起来好多细节要处理

百度之星 2015 复赛 1001 (数长方形)

数长方形    Accepts: 595    Submissions: 1225  Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description 小度熊喜欢玩木棒。一天他在玩木棒的时候,发现一些木棒会形成长方形

百度之星 2015 初赛(1) 1002 找连续数

找连续数      Accepts: 401      Submissions: 1911  Time Limit: 2000/1000 MS (Java/Others)      Memory Limit: 32768/32768 K (Java/Others) Problem Description 小度熊拿到了一个无序的数组,对于这个数组,小度熊想知道是

2015多校联合训练第三场Work(hdu5326)

题意: a是b的上司,b是c的上司,则a是c的上司,问构成一个树种,有多人是 k个人的上司 思路: 先找出root,然后dfs一下就行 #include <bits/stdc++.h>#define LL long longusing namespace std;const int MAXN = 1e6;int f[105];int n, k;int mp[101][101];

2015年多校联合训练第三场RGCDQ(hdu5317)

题意: f(i)代表i数中有的素数的种数,给出区间[l,r],求区间内max(gcd(f(i))), 由于i最大是1e6,2*3*5*7*11*13*17>1e6,故最多不超过7种素数, 先打表打出1e6内的素数种数表,然后用sum[i][j]代表1-i个数中,还有j个素数的个数,最后用sum[r][j] - sum[l-1][j]求出区间内含有j个素数的数的个数,暴力找出1,2,3,4,5

2015多校联合训练第一场Tricks Device(hdu5294)

题意:给一个无向图,给起点s,终点t,求最少拆掉几条边使得s到不了t,最多拆几条边使得s能到t 思路: 先跑一边最短路,记录最短路中最短的边数,总边数-最短边数就是第二个答案 第一个答案就是在最短路里面求最小割,也就是求最大流,然后根据最短路在建个新图,权为1,跑一边网络流 模板题,以后就用这套模板了 #include <iostream>#include <cstdio>#incl

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

2015年多校联合训练第一场OO’s Sequence(hdu5288)

题意:给定一个长度为n的序列,规定f(l,r)是对于l,r范围内的某个数字a[i],都不能找到一个对应的j使得a[i]%a[j]=0,那么l,r内有多少个i,f(l,r)就是几。问所有f(l,r)的总和是多少。 公式中给出的区间,也就是所有存在的区间。 思路:直接枚举每一个数字,对于这个数字,如果这个数字是合法的i,那么向左能扩展的最大长度是多少,向右能扩展的最大长度是多少,那么i为合法的情况