@ 蓝桥杯 练习系统 历届试题 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()); }
}
}