题目
A 国与 B 国每年都会举办一场友谊赛。该友谊赛在两国之间已举办多年,比赛规则如下:
比赛中,两国各派出 N 名参赛者,各国参赛者站成一排,面对面站立。然后,两国各派出站位相连的 K 名参赛者组成代表选手,作为一组进行比拼。比拼后,两国各自的 K 名选手返回初始位置,重新派出站位相连的 K 名选手组成队伍,进行多次比赛。注意,相同选手的组合仅能比拼一次。换句话说,如果 A 国的 1、2、3 号位选手与 B 国的 1、2、3 号位选手组队进行过一次比拼,则 A 国的 1、2、3 号位选手与 B 国的 1、2、3 号位选手都不得再次组队比拼。两国以这种方式进行比拼,直到无法再进行下去。
但是,由于是友谊赛,我们希望两国派出的站位相连的 K 名选手的能力值相加后的差值绝对值小于 X。
假设友谊赛按照上述条件进行,请算出两国之间比拼的总次数。
假设在五名选手中派出站位相连的三名参加比拼(如下所示),要求比拼中两国三名队员能力值之和的差值不大于2。
A 国选手能力值: 1 1 1 4 2
B 国选手能力值: 2 1 1 5 3
如果 A 国派出 1、2、3 号位选手组成一队(以下简称为 A123 队,A 国的能力值为 3),B 国只能派出其 1、2、3 号位选手组成队伍(以下简称为 B123 队,B 国的能力值为 4)与之比拼。除了可以和 A123 队(能力值之和为 3)比拼之外,B 国的 B123 队(能力值之和为 4)还可以与 A 国的 A234 队(能力值之和为 6)进行比拼,但是不能与 A345 队(能力值之和为 7)比拼。按此规则计算总比拼次数,则次数等于五。(A123 对 B123、A234 对 B123、A234 对 B234、A345 对 B234 以及 A345 对 B345)
[限制条件]
- 各国参赛者数量 N 为介于 3 到 100,000 之间的整数。
- 参与比拼的代表选手数量 K 为介于 2 到 N 之间的整数。
- 各选手的能力值为介于 1 到 100,000 之间的整数。
- 友谊赛的能力值差值 X 为介于 0 到 1,000,000,000 之间的整数。
[输入]
首先,给定测试用例数量 T,后面接着输入 T 种测试用例。在各个测试用例的第一行,给定两国参赛者数量 N、参与比拼的选手数量 K,以及比拼要求的能力值差值 X,以空格分隔。在第二行,按站位给定从 1 到 N 号位的 A 国 N 名选手的能力值,以空格分隔。在第三行,按站位给定从 1 到 N 号位的 B 国 N 名选手的能力值,以空格分隔。
[输出]
每个测试用例输出一行。首先,输出 “#x”(x 为测试用例编号,从 1 开始),加一个空格,然后输出案例规定条件下可进行的比拼总次数。
[输入和输出示例]
(输入)
3
5 3 2
1 1 1 4 2
2 1 1 5 3
10 3 3
2 2 2 2 2 3 3 3 3 3
1 1 1 1 1 2 2 2 1 1
5 3 100
10000 10 1000 100 1
1 2 3 4 5
(输出)
#1 5
#2 35
#3 0
思路:
-
先求出A、B数组连续区间长度为K的区间和数组SUM_A、SUM_B;
-
便利A数组的每个元素Ai,求出在SUM_B中,[Ai - X, Ai + X] 区间内的元素个数COUNTi;
实现方式一(二分查找):
对数组SUM_B进行排序后二分查找,找出从左往右的第一个大于等于【Ai - X】的下标s,以及最后一个小于等于【Ai + X】的下标e,则 COUNTi = e - s + 1。(小技巧:因为SUM_B元素均为整数,所以求SUM_B中最后一个小于等于【Ai + X】的下标e,可以转化为求SUM_B中最后一个小于等于【Ai + X + 1】的下标,再减去1)实现方式二(双指针):
对数组SUM_A、SUM_B排序,初始化 s = 0,e = 0;
遍历SUM_A,while循环,若 SUM_B[s] < Ai - X 则s++(即:找出从左往右的第一个大于等于【Ai - X】的下标s);
while循环,若 SUM_B[e] >= Ai + X 则e++;最后e–(即:找出从左往右的最后一个小于等于【Ai + X】的下标e);
则 COUNTi = e - s + 1。 -
累加每个COUNT到ASW,则ASW即为所求。
代码(二分查找):
import java.io.*;
import java.util.*;
public class Main {
static int T, N, K;
static long X, ASW;
static int[] ARR_A;
static int[] ARR_B;
static long[] SUM_A;
static long[] SUM_B;
public static void main(String[] args) throws Exception {
System.setIn(new FileInputStream("D:\\SW\\TestCase\\sample_input_20210803.txt"));
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
T = Integer.parseInt(st.nextToken());
for (int t = 1; t <= T; t++) {
st = new StringTokenizer(br.readLine());
N = Integer