1. 程式人生 > 其它 >墊腳石 - Stepping Stones - Indexed Tree

墊腳石 - Stepping Stones - Indexed Tree

墊腳石

(測試用例總數:40 個,1.5 秒 (C/C++),2 秒 (JAVA)/記憶體要求:256 M,堆疊 1 M)

Lia 在一個景點看到了由 N 個墊腳石組成的石橋。單純地走過這些墊腳石感覺沒有意思,所以她給每塊墊腳石設定了一個分數,將踩到的所有石頭上的分數全部加起來,想要得到一個最大分數。

但是,為了讓這件事更有意思,她決定按下列規則來過橋。

1.第一塊和最後一塊墊腳石必須要踩。

2.設定一個K值,下一塊踩的石頭與上一塊踩的石頭間相隔的距離最大為 K。

3.不能重複踩同一塊墊腳石。

[圖]

假設 N 是 7,每個石頭的分數如上圖所示。如果 K 是 2,按 ① → ② → ④ → ⑥ → ⑦ 的方式移動可以獲得最高分數,分數是 1 (-6 + -4 + 4 + -2 + 9)。如果 K 是 3,按 ① → ④ → ⑦ 的方式移動可以獲得最高分數,分數是 7 (-6 + 4 + 9)。

請幫助 Lia 計算出按規則踩著墊腳石過橋時,可以獲得的最高分數

[限制條件]

1.組成橋的墊腳石數量 N 為介於 1 到 300,000 之間的整數。

2.每個墊腳石的分數在帶符號的 32 位整數值範圍內。

3.K 為介於 1 到 N 之間的整數。

[輸入]

首先,給定測試用例數量 T,後面接著輸入 T 種測試用例。在每個測試用例的第一行,給定墊腳石數量 N 和距離 K,以空格分隔。在下一行,給定從 1 到 N 號墊腳石每個的分數,以空格分隔。

[輸出]

每行輸出一個測試用例。首先,輸出“#x”(其中 x 表示測試用例編號,從 1 開始)加上一個空格,然後輸出問題中要求的值。

[輸入和輸出示例]

(輸入)

3
7 2
-6 -4 -6 4 -4 -2 9
7 3
-6 -4 -6 4 -4 -2 9
10 2
-3 -4 -2 -1 -7 -5 -9 -4 -7 -5

(輸出)

#1 1
#2 7
#3 -20

思路分析:
從第二個元素開始,求前K個元素的最大值+當前值,求最大值時,並非從原陣列中求,而且從得到的最大值陣列中求
基本思想是每步都計算最優解,當前元素的最優解是從前K個元素的最優解中得來
求當前元素之前K個元素的最大值,可用Indexed Tree計算

package tree;

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

/**
 * 從第二個元素開始,求前K個元素的最大值+當前值,求最大值時,並非從原陣列中求,而且從得到的最大值陣列中求
 * 基本思想是每步都計算最優解,當前元素的最優解是從前K個元素的最優解中得來
 * 求當前元素之前K個元素的最大值,可用Indexed Tree計算
 * @author XA-GDD
 *
 */
public class EQ_SteppingStones_0827 {
	static int T,N,K;
	static int _Max_N = 300000;
	static int [] srcArr = new int[_Max_N];
	static long [] idxTree = new long[_Max_N*4];
	static int offset;
	public static void main(String[] args) throws IOException {
		System.setIn(new FileInputStream("D:\\workspace\\sw_pro\\test_case\\sample_input_0827.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(srcArr, 0);
	    	Arrays.fill(idxTree, Long.MIN_VALUE);
	    	
	    	st = new StringTokenizer(br.readLine());
	    	N = Integer.parseInt(st.nextToken());
	    	K = Integer.parseInt(st.nextToken());
	    	
	    	st = new StringTokenizer(br.readLine());
	    	for(int i=0;i<N;i++) {
	    		srcArr[i]=Integer.parseInt(st.nextToken());
	    	}
	    	
	    	
	    	int k=0;
	    	while((1<<k)<N) {
	    		k++;
	    	}
	    	offset = 1<<k;
	    	
	    	
	    	for(int i=0;i<N;i++) {
	    		update(offset+i,srcArr[i]);
	    	}
	    	
	    	for(int i=1;i<N;i++) {
	    		long val = getMaxBefK(i);
	    		update(offset+i,val+srcArr[i]);
	    	}
	    	System.out.printf("#%d %d\n",testCase,idxTree[offset+N-1]);
	    }

	}
	
	static long getMaxBefK(int idx) {		
		int s = idx-K>0?offset+idx-K:offset;
		int e = idx-1>0?offset+idx-1:offset;
		return query(s,e);
	}
	
	static void update(int index,long val) {
		idxTree[index]=val;
		index=index>>1;
	    while(index>0) {
	    	idxTree[index] = Math.max(idxTree[index*2], idxTree[index*2+1]);
	    	index=index>>1;
	    }
	}
	
	static long query(int s, int e) {
		long res=Long.MIN_VALUE;
		while(s<=e) {
			if(s%2==1) {
				res = Math.max(res, idxTree[s]);
			}
			if(e%2==0) {
				res = Math.max(res, idxTree[e]);
			}
			s = (s+1)>>1;
			e = (e-1)>>1;
		}
		return res;
	}

}