[hdu5247]rmq+预处理

题意:有一个无序数组,求有多少个长度为k的区间满足把区间内的数排序后是连续的。

思路:长度为k的区间排序后是 连续的数等价于maxval-minval等于k-1并且不同的数有k个(或者说没有相同的数),第一个条件可以用rmq快速得到区间最大值与最小值之差,第二个条件可以这样求,按区间的左边界分类预处理,遍历右边界,如果[L,R]内有相同的数,则[L,R+k]有相同的数,否则转化为判断a[R+1]是否在区间[L,R]内出现过,维护一个last数组,last[i]表示i上一次出现的位置,那么等价于判断last[a[R+1]]是否>=L,由于a[i]很大,所以需离散后处理。


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cstdlib>

#include <algorithm>

#include <vector>

using namespace std;

typedef long long LL;

#define all(a) (a).begin(), (a).end()

const int maxn = 1e4 + 7;

struct ST {

    struct Node {

        int a[22];

        int &operator [] (int x) {

            return a[x];

        }

    };

    const static int maxn = 1e6 + 7;

    vector<Node> dp;

    static int index[maxn];

    static void init_index() {

        index[1] = 0;

        for (int i = 2; i < maxn; i ++) {

            index[i] = index[i - 1];

            if (!(i & (i - 1))) index[i] ++;

        }

    }

    void init_min(vector<int> &a) {

        int n = a.size();

        dp.resize(n);

        for (int i = 0; i < n; i ++) dp[i][0] = a[i];

        for (int j = 1; (1 << j) <= n; j ++) {

            for (int i = 0; i + (1 << j) - 1 < n; i ++) {

                dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);

            }

        }

    }

    void init_max(vector<int> &a) {

        int n = a.size();

        dp.resize(n);

        for (int i = 0; i < n; i ++) dp[i][0] = a[i];

        for (int j = 1; (1 << j) <= n; j ++) {

            for (int i = 0; i + (1 << j) - 1 < n; i ++) {

                dp[i][j] = max(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);

            }

        }

    }

    int query_min(int L, int R) {

        int p = index[R - L + 1];

        return min(dp[L][p], dp[R - (1 << p) + 1][p]);

    }

    int query_max(int L, int R) {

        int p = index[R - L + 1];

        return max(dp[L][p], dp[R - (1 << p) + 1][p]);

    }

};

int ST::index[maxn];

ST st1, st2;

vector<int> a, b;

bool chk[maxn][1000];

int last[maxn];

int main() {

#ifndef ONLINE_JUDGE

    freopen("in.txt""r", stdin);

#endif // ONLINE_JUDGE

    puts("Case #1:");

    int n, m;

    cin >> n >> m;

    a.resize(n);

    for (int i = 0; i < n; i ++) {

        scanf("%d", &a[i]);

    }

    b = a;

    ST::init_index();

    st1.init_max(a);

    st2.init_min(a);

    sort(all(a));

    a.erase(unique(all(a)), a.end());

    for (int i = 0; i < n; i ++) {

        b[i] = lower_bound(all(a), b[i]) - a.begin();

    }

    for (int i = 0; i < n; i ++) {

        chk[i][1] = true;

        memset(last, 0xff, sizeof(last));

        last[b[i]] = i;

        for (int L = 2; i + L - 1 < n && L <= 1000; L ++) {

            if (last[b[i + L - 1]] >= i) break;

            last[b[i + L - 1]] = i + L - 1;

            chk[i][L] = true;

        }

    }

    for (int i = 0; i < m; i ++) {

        int k;

        scanf("%d", &k);

        int ans = 0;

        for (int i = 0; i + k - 1 < n; i ++) {

            ans += st1.query_max(i, i + k - 1) - st2.query_min(i, i + k - 1) == k - 1 && chk[i][k];

        }

        printf("%d\n", ans);

    }

    return 0;

}

时间: 2024-10-14 09:14:20

[hdu5247]rmq+预处理的相关文章

codeforces 279C C. Ladder(rmq+预处理)

题目连接: codeforces 279C 题目大意: 给出一个序列,m次查询,每次给出一个子串,问这个子串是否满足,中间能够找到一个元素,让这个元素作为前后分别单调的分界. 题目分析: 首先对于每次查询,我们知道分界一定是最大的元素,所以我们可以用rmq预处理出区间最大. 然后为了判断这个区间是否能够通过最大的元素作为分界点而前后单调,我们可以通过预处理,正向和反向分别扫一遍,记录某一个点的为最大元素的能够向左和向右得到的最长的单调子串的长度,然后每次只需要O(1)的判断就可以,判断当前元素最

hdu5289 RMQ+二分

RMQ预处理最大值,最小值,然后对于每一点,二分可能满足的区间长度,长度-1就是该店开始的区间满足的个数. #include<stdio.h> #include<string.h> #include<math.h> #define maxn 100010 #define LL __int64 int dp1[maxn][20],n,a[maxn],dp2[maxn][20]; int min(int x,int y) {return x<y?x:y;} int m

POJ3693:Maximum repetition substring(后缀数组+RMQ)

Description The repetition number of a string is defined as the maximum number R such that the string can be partitioned into R same consecutive substrings. For example, the repetition number of "ababab" is 3 and "ababa" is 1. Given a

HDU 5726 GCD (RMQ + 二分)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5726 给你n个数,q个询问,每个询问问你有多少对l r的gcd(a[l] , ... , a[r]) 等于的gcd(a[l'] ,..., a[r']). 先用RMQ预处理gcd,dp[i][j] 表示从i开始2^j个数的gcd. 然后用map存取某个gcd所对应的l r的数量. 我们可以在询问前进行预处理,先枚举i,以i为左端点的gcd(a[i],..., a[r])的种类数不会超过log2(n)

LA 6531 Go up the Ultras 单调栈+RMQ

题意:已经懒得吐槽了..有N个山峰,(N<=10^5),每个山峰有高度h,对应着每个山峰有一个d值,每个山峰到所有其他的严格比 它高的山峰都会经过一个最低值(山谷),d代表是h减去这些最低值中的最大值的差(如果不存在比它高的山峰那么d就是它本身的 高度),问有多少山峰的d>=150000米. 思路:利用单调栈维护每个峰左边第一个比它高的峰的位置l,右边第一个比它高的峰的位置r,对于r,我们从前向后维护一个单调减 序列,如果当前考虑的点i比栈顶的元素高度高,那么弹出栈顶元素,并将它的r置为i,直

FZU2136--取糖果 (线段树+RMQ)

Problem Description 有N个袋子放成一排,每个袋子里有一定数量的糖果,lzs会随机选择连续的几个袋子,然后拿走这些袋子中包含最多糖果的袋子.现问你,在选择x个袋子的情况下,lzs最坏情况下,也就是最少会拿到多少个糖果?对于x取值为1到n都分别输出答案. Input 第一行一个整数T,表示有T组数据. 每组数据先输入一行一个整数N(1<=N<=100000),表示袋子数,接下来一行输入N个正整数,输入的第i个数表示第i个袋子所装的糖果数. Output 每组数据输出n行,第i行

HDU 4123 Bob’s Race(RMQ)

题意是说给出一棵树,N(10^5)个顶点,以及每条边的权值,现在需要选择连续的K个点(顶点编号连续),可以被选出来的条件是: 若d[i]代表顶点i到树上其他点的距离的最大值,使得区间[a, b]的d值的最大差值不大于Q, 也就是max(d[a], d[a + 1], ..., d[b]) - max(d[a], d[a + 1], ..., d[b]) <= Q Q是给出的一个查询(共有m<=500个查询),求对应每一个查询的K的最大值 思路是首先预处理出每个点到其他点的最大距离, 这可以通过

Codeforces Round #172 (Div. 2)---D. Maximum Xor Secondary(RMQ + 二分)

Bike loves looking for the second maximum element in the sequence. The second maximum element in the sequence of distinct numbers x1,?x2,?-,?xk (k?>?1) is such maximum element xj, that the following inequality holds: . The lucky number of the sequenc

2019杭电多校十 1011 Make Rounddog Happy(rmq + 分治)

题意 有一个大小为 \(n ,(n \leq 3e5)\) 的序列,序列中的每一个数 \(a_i\) 满足\(1 \leq a_i \leq n\), 现定义 good subarray:对于一段区间\(a_l, a_{l+1}, \dots, a_r\),满足区间内无重复元素并且 \(\max\{a_l, a_{l+1}, \dots, a_r\} - (r-l+1) \leq k\). 求序列a中的 good subarray的数量. 思路 rmq + 分治的套路题. 针对最大值,可通过rm