友谊赛 - Friendly Match - 累加和&二分查找

友谊赛

(测试用例总数:X,1.5 秒 (C/C++),2 秒 (JAVA)/内存要求:256 M,堆栈 1 M)

 

A 国与 B 国每年都会举办一场友谊赛。该友谊赛在两国之间已举办多年,比赛规则如下:

比赛中,两国各派出 N 名参赛者,各国参赛者站成一排,面对面站立。然后,两国各派出站位相连的 K 名参赛者组成代表选手,作为一组进行比拼。比拼后,两国各自的 K 名选手返回初始位置,重新派出站位相连的 K 名选手组成队伍,进行多次比赛。注意,相同选手的组合仅能比拼一次。换句话说,如果 A 国的 1、2、3 号位选手与 B 国的 1、2、3 号位选手组队进行过一次比拼,则 A 国的 1、2、3 号位选手与 B 国的 1、2、3 号位选手都不得再次组队比拼。两国以这种方式进行比拼,直到无法再进行下去。

但是,由于是友谊赛,我们希望两国派出的站位相连的 K 名选手的能力值相加后的差值绝对值小于 X

假设友谊赛按照上述条件进行,请算出两国之间比拼的总次数

假设在五名选手中派出站位相连的三名参加比拼(如下所示),要求比拼中两国三名队员能力值之和的差值不大于二。

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)

 

[限制条件]

1. 各国参赛者数量 N 为介于 3 到 100,000 之间的整数。

2. 参与比拼的代表选手数量 K 为介于 2 到 N 之间的整数。

3. 各选手的能力值为介于 1 到 100,000 之间的整数。

4. 友谊赛的能力值差值 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

 

思路:
1.分别求出A、B两组所有连续K个数的累加和;
2.将B组排序,遍历A组,从B中找A组元素-X至与找A组元素+X之间的元素的个数
3.由于数量级为10W,因此只能使用时间复杂度为O(NlogN)的算法
4.B中如果有相同的元素,A组元素-X对应的index应该取最小的,A组元素+X对应的index应该取最大的
5.由于B已排序,因此二分查找最快,且由于4的限制,Arrays.binarySearch()不满足,需自定义二分查找的方法

 

package pro;

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

/**
 * 思路:
 * 1.分别求出A、B两组所有连续K个数的累加和;
 * 2.将B组排序,遍历A组,从B中找A组元素-X至与找A组元素+X之间的元素的个数
 * 3.由于数量级为10W,因此只能使用时间复杂度为O(NlogN)的算法
 * 4.B中如果有相同的元素,A组元素-X对应的index应该取最小的,A组元素+X对应的index应该取最大的
 * 5.由于B已排序,因此二分查找最快,且由于4的限制,Arrays.binarySearch()不满足,需自定义二分查找的方法
 * 
 * @author XA-GDD
 *
 */
public class FriendlyMatch_0803 {
	static int T,N,K;
	static long X;
	static int _max_Nval = 100000;
	static int arrA [] = new int [_max_Nval+2];
	static int arrB [] = new int [_max_Nval+2];
	static long sumA [] = new long [_max_Nval];
	static long sumB [] = new long [_max_Nval];
	static int sumArrLength;
	static long ANS;
	
	public static void main(String[] args) throws IOException {
		System.setIn(new FileInputStream("D:\\workspace\\sw_pro\\test_case\\sample_input_0803.txt"));
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		T = Integer.parseInt(st.nextToken());
		for(int testCase=1;testCase<=T;testCase++) {
			Arrays.fill(arrA, 0);
			Arrays.fill(arrB, 0);
			Arrays.fill(sumA, 0L);
			Arrays.fill(sumB, 0L);
			ANS=0L;
			sumArrLength=0;
			
			st = new StringTokenizer(br.readLine());
			N = Integer.parseInt(st.nextToken());
			K = Integer.parseInt(st.nextToken());
			X = Long.parseLong(st.nextToken());
			
			st = new StringTokenizer(br.readLine());
			for(int i=0;i<N;i++) {
				arrA[i] = Integer.parseInt(st.nextToken());
			}
			
			st = new StringTokenizer(br.readLine());
			for(int i=0;i<N;i++) {
				arrB[i] = Integer.parseInt(st.nextToken());
			}
			
			//分别求K个数的累加和,时间复杂度O(N)
			sumA = getSumOfK(arrA);
			sumB = getSumOfK(arrB);
			
			Arrays.sort(sumB,0,sumArrLength);
			
			//遍历A数组,时间复杂度O(N)
			for(int i=0;i<sumArrLength;i++) {
				//二分查找,时间复杂度O(logN)
				int low = getLowBound(sumB,sumA[i]-X);
				int high = getHighBound(sumB,sumA[i]+X);			
				int matchCnt = high-low;							
				
				ANS += (long)matchCnt;
			}

	
			System.out.println("#"+testCase+" "+ANS);
		}
	}
	
	static long[] getSumOfK(int arr[]) {
		long [] sumArr = new long[_max_Nval];
		long sum = 0L;
		for(int i=0;i<K;i++) {
			sum += (long)arr[i];
		}
		sumArr[0] = sum;
		int index=0;
		for(int i=K;i<N;i++) {
			sum -= (long)arr[index++];
			sum += (long)arr[i];
			sumArr[index] = sum;
		}
		sumArrLength = index+1;
		return sumArr;
	}
	
	//低位,返回index最小位置
	static int getLowBound(long arr[], long target) {
		int low=0;
		int high=sumArrLength;
		
		while (low < high) {
			int mid = (low + high) /2;
			long mdiVal = arr[mid];
			if(target<=mdiVal) {
				high = mid;
			}else {
				low = mid+1;
			}
		}	
		return low; 
	}
	
	//高位,返回index最大+1位置
	static int getHighBound(long arr[], long target) {
		int low=0;
		int high=sumArrLength;
		
		while (low < high) {
			int mid = (low + high) /2;
			long mdiVal = arr[mid];
			if(target>=mdiVal) {
				low = mid+1;
			}else {
				high = mid;
			}
		}	
		return low; 
	}

}

  

posted @ 2022-01-20 21:11  晓暮云  阅读(100)  评论(0编辑  收藏  举报