历届试题 连号区间数

@ 蓝桥杯 练习系统 历届试题 PREV-7

资源限制

时间限制:1.0s 内存限制:256.0MB


问题描述

小明这些天一直在思考这样一个奇怪而有趣的问题:

在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是:

如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增排序后能得到一个长度为R-L+1的“连续”数列,则称这个区间连号区间。

当N很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助。


输入格式

第一行是一个正整数N (1 <= N <= 50000), 表示全排列的规模。

第二行是N个不同的数字Pi(1 <= Pi <= N), 表示这N个数字的某一全排列。


输出格式

输出一个整数,表示不同连号区间的数目。


测试样例1

in: 
4
3 2 4 1

out:
7

测试样例2

in: 
5
3 4 2 5 1

out:
9

AC code:

import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {

    public static void main(String[] args) throws IOException {
        InputReader in = new InputReader(System.in, " ");
        int n = in.nextInt(), cnt = 0;
        int[] value = new int[n + 1];
        for (int i = 1; i <= n; i++)
            value[i] = in.nextInt();
        for (int i = 1, max, min; i < n; i++) {
            max = min = value[i];
            for (int j = i + 1; j <= n; j++) {
                if (max < value[j]) max = value[j];
                if (min > value[j]) min = value[j];
                if (max - min == j - i) cnt++;
            }
        }
        System.out.print(cnt + n);
    }

    static class InputReader {

        BufferedReader read;
        StringTokenizer tok;
        String delimiters;

        InputReader(InputStream in) { this(in, " \n\t\r\f"); }

        InputReader(InputStream in, String delimiters) {
            this.read = new BufferedReader(new InputStreamReader(in));
            this.tok = new StringTokenizer("", this.delimiters = delimiters);
        }

        String next() {
            while (!tok.hasMoreTokens())
                try {
                    tok = new StringTokenizer(read.readLine(), delimiters);
                } catch (IOException e) { }
            return tok.nextToken();
        }

        int nextInt() { return Integer.parseInt(next()); }
    }
}

因为给出的是某个全排列,所以区间中排序后最大值与最小值之间的距离等于区间长的话,那就代表此区间为连续区间

所以考虑到会频繁的查找区间最大值最小值,一开始我就使用了线段树,结果就是下面这个结果

没要考虑到区间之间的处理覆盖
打个比方就是 1 - 3 的结果是可以覆盖在 1 - 2 之上的

懂得都懂,不懂的其实我也不懂

再就是题目没说,但连续区间包括区间长度为1的情况,所以跳过了这段的处理,结果直接加 N 即可


线段树 (TLE)

import java.io.IOException;
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {

    static Node root;
    static int[] value;

    public static void main(String[] args) throws IOException {
        InputReader in = new InputReader(System.in, " ");
        int n = in.nextInt(), cnt = 0;
        value = new int[n + 1];
        for (int i = 1; i <= n; i++)
            value[i] = in.nextInt();
        build(root = new Node(1, n));
        for (int i = 1; i < n; i++)
            for (int j = i + 1; j <= n; j++) {
                value = query(i, j, root);
                if (value[0] - value[1] == j - i) cnt++;
            }
        System.out.print(cnt + n);
    }

    static void build(Node node) {
        if (node.l != node.r) {
            int mid = (node.l + node.r) / 2;
            build(node.left = new Node(node.l, mid));
            build(node.right = new Node(mid + 1, node.r));
            node.max = max(node.left.max, node.right.max);
            node.min = min(node.left.min, node.right.min);
        } else node.max = node.min = value[node.l];
    }

    static int[] query(int l, int r, Node n) {
        if (l <= n.l && r >= n.r) return new int[]{ n.max, n.min };
        int res[] = {0, Integer.MAX_VALUE}, mid = (n.l + n.r) / 2;
        if (l <= mid) res = query(l, r, n.left);
        if (r > mid) {
            int[] temp = query(l, r, n.right);
            res = new int[]{max(res[0], temp[0]), min(res[1], temp[1])};
        }
        return res;
    }

    static int max(int a, int b) { return a > b? a: b; }

    static int min(int a, int b) { return a < b? a: b; }

    static class Node {

        int l, r, max, min;
        Node left, right;

        Node(int l, int r) {
            this.l = l;
            this.r = r;
        }
    }

    static class InputReader {

        BufferedReader read;
        StringTokenizer tok;
        String delimiters;

        InputReader(InputStream in) { this(in, " \n\t\r\f"); }

        InputReader(InputStream in, String delimiters) {
            this.read = new BufferedReader(new InputStreamReader(in));
            this.tok = new StringTokenizer("", this.delimiters = delimiters);
        }

        String next() {
            while (!tok.hasMoreTokens())
                try {
                    tok = new StringTokenizer(read.readLine(), delimiters);
                } catch (IOException e) { }
            return tok.nextToken();
        }

        int nextInt() { return Integer.parseInt(next()); }
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值