墊腳石 - 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; } }