【JAVA】求数列中相邻两数间不存在比两数大的情况数(Pro20211203)(IndexTree / DP)

【JAVA】求数列中相邻两数间不存在比两数大的情况数(Pro20211203)(IndexTree / DP)

题目

身高各异的 N 个人按一定间隔站成一排,每个人都按照以下规则来监控他们能看到的人是否在做其他的事。

  • 规则:我和我要监控到的第 i 个人之间不能有人比我高,
    也不能有人比第 i 个人高。例如,根据下 [图] 可知,⑤ 号可以监控到 ③ 号,
    但无法监控到 ① 号,因为 ③ 号比 ⑤ 号高。
    在这里插入图片描述

假设如上 [图] 所示,一共站着八个人。从左向右将这些人编为 ①-⑧ 号,他们的身高即为各自头上的数字。
对 ① 号而言,他左边没有可用监控到的人。在右边,① 号可以监控比 ② 号高的 ③ 号,但无法监控比 ③ 号矮的 ④ 号和 ⑤ 号。此外,因为中间没有更高的人,所以可以一直监控到 ⑥ 号,但无法监控比 ⑥ 号矮的 ⑦ 号和 ⑧ 号。也就是说,① 号可以监控 ② 号、③ 号和 ⑥ 号。对 ② 号而言,既可以监控左边的 ① 号,又可以监控右边的 ③ 号。但右边 ③ 号的身高比 ② 号的高,② 号无法监控右边其余的人。③ 号可以监控左边的 ① 号和 ② 号,以及右边的 ④ 号、⑤ 号和 ⑥ 号;但无法监控 ⑦ 号和 ⑧ 号,因为站在中间的 ⑥ 号比 ⑦ 号和 ⑧ 号高。⑥ 号可以监控左边的 ① 号、③ 号和 ⑤ 号,以及右边的 ⑦ 号和 ⑧ 号。
根据给定的身高数据,计算每个人可在左右两边监控到的总人数。
※ 根据上 [图] 可知,① 号可以监控三个人(② 号、③ 号和 ⑥ 号),② 号可以监控两个人(① 号和 ③ 号),③ 号可以监控五个人(① 号、② 号、④ 号、⑤ 号和 ⑥ 号),④ 号可以监控两个人(③ 号和 ⑤ 号),⑤ 号可以监控三个人(③ 号、④ 号和 ⑥ 号),⑥ 号可以监控五个人(① 号、③ 号、⑤ 号、⑦ 号和 ⑧ 号),⑦ 号可以监控两个人(⑥ 号和 ⑧ 号),⑧ 号可以监控两个人(⑥ 号和 ⑦ 号)。

[限制条件]
1.站立之人的数量 N 为介于 1 到 300,000 之间的整数。
2.站立之人的身高 M 为介于 1 到 1,000,000,000 之间的整数。
3.所有人的身高都不相同。

[输入]
首先,给定测试用例数量 T,后面接着输入 T 种测试用例。在测试用例第一行给出人数 N。在第二行给出 N 个人的身高,以空格分隔。

[输出]
每行输出一个测试用例。每个测试用例都输出“#x”(x 为测试用例的编号,从 1 开始)以及每个人两边可以监控的总人数。

[输入和输出示例]
(输入)
2
8
10 3 8 4 7 9 5 6
7
1 2 3 10 9 8 7

(输出)
#1 24
#2 12

解题思路

拆成两部分,从左到右算一遍每个人监控的人数,再从右到左算一遍每个人可监控的人数
以从左到右为例
1.第一个循环利用双向队列求出每个人右边第一个比他高的人的位置
2.第二个循环利用动态规划算出每个人的最长上升子序列人数数量
3.第三个循环计算第i个人可以监控的人数
如果i+1个人比第i个人高,那么可监控人数就是1
如果i+1个人比第i个人矮,那么就是第i+1个人的最长上升子序列人数数量 - 右边第一个比第i个人高的那个人的最长上升子序列人数 +1(如果有比第i个人高的人存在,没有就是+0),再按上面逻辑从右到左算一遍

代码(IndexTree)


import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.Comparator;
import java.util.StringTokenizer;

public class Pro20211203IndexTree {
	static int asw, tree[];

	public static void update(int i, int val) {
		while (i > 0) {
			tree[i] += val;
			i /= 2;
		}
	}

	public static int query(int s, int e) {
		int result = 0;
		while (s <= e) {
			if (s % 2 > 0)
				result += tree[s];
			if (e % 2 == 0)
				result += tree[e];

			s = (s + 1) / 2;
			e = (e - 1) / 2;
		}

		return result;
	}

	public static void main(String[] args) throws Exception {
		System.setIn(new FileInputStream("D:\\SW\\TestCase\\sample_input_20211203.txt"));

		long s = System.currentTimeMillis();
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		int T = Integer.parseInt(br.readLine());

		for (int t = 1; t <= T; t++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			int N = Integer.parseInt(st.nextToken());

			int idx = 1;
			while (idx < N)
				idx = idx << 1;

			int[][] data = new int[N][2];
			tree = new int[idx * 2];

			asw = 0;

			st = new StringTokenizer(br.readLine());
			for (int i = 0; i < N; i++) {
				data[i][0] = Integer.parseInt(st.nextToken());
				data[i][1] = i;
			}

			Arrays.sort(data, 0, N, new Comparator<int[]>() {
				@Override
				public int compare(int[] o1, int[] o2) {
					return o2[0] - o1[0];
				}
			});

			for (int i = 0; i < N; i++) {
				int count = query(idx, idx + data[i][1] - 1) > 0 ? 1 : 0;
				count += query(idx + data[i][1] + 1, 2 * idx - 1) > 0 ? 1 : 0;

				asw += 2 * count;

				update(idx + data[i][1], 1);
			}

			System.out.println("#" + t + " " + asw);
		}

		long e = System.currentTimeMillis();

		System.out.println(e - s);
	}
}

代码(DP)


import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.Set;
import java.util.StringTokenizer;

public class Pro20210924Topology {
	static int T, N, M, ASW, IN[];
	static Set<Integer>[] DATA;

	public static void main(String[] args) throws Exception {
		System.setIn(new FileInputStream("D:\\SW\\TestCase\\sample_input_20210924.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		T = Integer.parseInt(br.readLine());

		for (int t = 1; t <= T; t++) {
			StringTokenizer st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			M = Integer.parseInt(st.nextToken());
			ASW = N;

			IN = new int[N + 1];
			DATA = new HashSet[N + 1];
			for (int n = 1; n <= N; n++)
				DATA[n] = new HashSet<Integer>();

			for (int a, b, m = 0; m < M; m++) {
				st = new StringTokenizer(br.readLine());
				a = Integer.parseInt(st.nextToken());
				b = Integer.parseInt(st.nextToken());

				if (DATA[a].add(b) && ++IN[b] == 1) ASW--;
			}

			if (ASW == 1) ASW = 0;

			for (int n = 1; n <= N; n++) {
				if (IN[n] > 0) continue;

				for (int next : DATA[n])
					if (IN[next] == 1) ASW++;
			}

			System.out.println(t + " " + ASW);
		}
	}
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值