@@ -67,34 +67,310 @@ nums[3] - nums[0] >= 3 - 0 。
67
67
68
68
<!-- 这里可写通用的实现逻辑 -->
69
69
70
+ ** 方法一:动态规划 + 树状数组**
71
+
72
+ 根据题目描述,我们可以将不等式 $nums[ i] - nums[ j] \ge i - j$ 转化为 $nums[ i] - i \ge nums[ j] - j$,因此,我们考虑定义一个新数组 $arr$,其中 $arr[ i] = nums[ i] - i$,那么平衡子序列满足对于任意 $j \lt i$,都有 $arr[ j] \le arr[ i] $。即题目转换为求在 $arr$ 中选出一个递增子序列,使得对应的 $nums$ 的和最大。
73
+
74
+ 假设 $i$ 是子序列中最后一个元素的下标,那么我们考虑子序列倒数第二个元素的下标 $j$,如果 $arr[ j] \le arr[ i] $,我们可以考虑是否要将 $j$ 加入到子序列中。
75
+
76
+ 因此,我们定义 $f[ i] $ 表示子序列最后一个元素的下标为 $i$ 时,对应的 $nums$ 的最大和,那么答案为 $\max_ {i=0}^{n-1} f[ i] $。
77
+
78
+ 状态转移方程为:
79
+
80
+ $$
81
+ f[i] = \max(\max_{j=0}^{i-1} f[j], 0) + nums[i]
82
+ $$
83
+
84
+ 其中 $j$ 满足 $arr[ j] \le arr[ i] $。
85
+
86
+ 我们可以使用树状数组来维护前缀的最大值,即对于每个 $arr[ i] $,我们维护前缀 $arr[ 0..i] $ 中 $f[ i] $ 的最大值。
87
+
88
+ 时间复杂度 $O(n \times \log n)$,空间复杂度 $O(n)$。其中 $n$ 为数组 $nums$ 的长度。
89
+
70
90
<!-- tabs:start -->
71
91
72
92
### ** Python3**
73
93
74
94
<!-- 这里可写当前语言的特殊实现逻辑 -->
75
95
76
96
``` python
77
-
97
+ class BinaryIndexedTree :
98
+ def __init__ (self , n : int ):
99
+ self .n = n
100
+ self .c = [- inf] * (n + 1 )
101
+
102
+ def update (self , x : int , v : int ):
103
+ while x <= self .n:
104
+ self .c[x] = max (self .c[x], v)
105
+ x += x & - x
106
+
107
+ def query (self , x : int ) -> int :
108
+ mx = - inf
109
+ while x:
110
+ mx = max (mx, self .c[x])
111
+ x -= x & - x
112
+ return mx
113
+
114
+
115
+ class Solution :
116
+ def maxBalancedSubsequenceSum (self , nums : List[int ]) -> int :
117
+ arr = [x - i for i, x in enumerate (nums)]
118
+ s = sorted (set (arr))
119
+ tree = BinaryIndexedTree(len (s))
120
+ for i, x in enumerate (nums):
121
+ j = bisect_left(s, x - i) + 1
122
+ v = max (tree.query(j), 0 ) + x
123
+ tree.update(j, v)
124
+ return tree.query(len (s))
78
125
```
79
126
80
127
### ** Java**
81
128
82
129
<!-- 这里可写当前语言的特殊实现逻辑 -->
83
130
84
131
``` java
85
-
132
+ class BinaryIndexedTree {
133
+ private int n;
134
+ private long [] c;
135
+ private final long inf = 1L << 60 ;
136
+
137
+ public BinaryIndexedTree (int n ) {
138
+ this . n = n;
139
+ c = new long [n + 1 ];
140
+ Arrays . fill(c, - inf);
141
+ }
142
+
143
+ public void update (int x , long v ) {
144
+ while (x <= n) {
145
+ c[x] = Math . max(c[x], v);
146
+ x += x & - x;
147
+ }
148
+ }
149
+
150
+ public long query (int x ) {
151
+ long mx = - inf;
152
+ while (x > 0 ) {
153
+ mx = Math . max(mx, c[x]);
154
+ x -= x & - x;
155
+ }
156
+ return mx;
157
+ }
158
+ }
159
+
160
+ class Solution {
161
+ public long maxBalancedSubsequenceSum (int [] nums ) {
162
+ int n = nums. length;
163
+ int [] arr = new int [n];
164
+ for (int i = 0 ; i < n; ++ i) {
165
+ arr[i] = nums[i] - i;
166
+ }
167
+ Arrays . sort(arr);
168
+ int m = 0 ;
169
+ for (int i = 0 ; i < n; ++ i) {
170
+ if (i == 0 || arr[i] != arr[i - 1 ]) {
171
+ arr[m++ ] = arr[i];
172
+ }
173
+ }
174
+ BinaryIndexedTree tree = new BinaryIndexedTree (m);
175
+ for (int i = 0 ; i < n; ++ i) {
176
+ int j = search(arr, nums[i] - i, m) + 1 ;
177
+ long v = Math . max(tree. query(j), 0 ) + nums[i];
178
+ tree. update(j, v);
179
+ }
180
+ return tree. query(m);
181
+ }
182
+
183
+ private int search (int [] nums , int x , int r ) {
184
+ int l = 0 ;
185
+ while (l < r) {
186
+ int mid = (l + r) >> 1 ;
187
+ if (nums[mid] >= x) {
188
+ r = mid;
189
+ } else {
190
+ l = mid + 1 ;
191
+ }
192
+ }
193
+ return l;
194
+ }
195
+ }
86
196
```
87
197
88
198
### ** C++**
89
199
90
200
``` cpp
91
-
201
+ class BinaryIndexedTree {
202
+ private:
203
+ int n;
204
+ vector<long long > c;
205
+ const long long inf = 1e18;
206
+
207
+ public:
208
+ BinaryIndexedTree(int n) {
209
+ this->n = n;
210
+ c.resize(n + 1, -inf);
211
+ }
212
+
213
+ void update(int x, long long v) {
214
+ while (x <= n) {
215
+ c[x] = max(c[x], v);
216
+ x += x & -x;
217
+ }
218
+ }
219
+
220
+ long long query (int x) {
221
+ long long mx = -inf;
222
+ while (x > 0) {
223
+ mx = max(mx, c[ x] );
224
+ x -= x & -x;
225
+ }
226
+ return mx;
227
+ }
228
+ };
229
+
230
+ class Solution {
231
+ public:
232
+ long long maxBalancedSubsequenceSum(vector<int >& nums) {
233
+ int n = nums.size();
234
+ vector<int > arr(n);
235
+ for (int i = 0; i < n; ++i) {
236
+ arr[ i] = nums[ i] - i;
237
+ }
238
+ sort(arr.begin(), arr.end());
239
+ arr.erase(unique(arr.begin(), arr.end()), arr.end());
240
+ int m = arr.size();
241
+ BinaryIndexedTree tree(m);
242
+ for (int i = 0; i < n; ++i) {
243
+ int j = lower_bound(arr.begin(), arr.end(), nums[ i] - i) - arr.begin() + 1;
244
+ long long v = max(tree.query(j), 0LL) + nums[ i] ;
245
+ tree.update(j, v);
246
+ }
247
+ return tree.query(m);
248
+ }
249
+ };
92
250
```
93
251
94
252
### **Go**
95
253
96
254
```go
255
+ const inf int = 1e18
256
+
257
+ type BinaryIndexedTree struct {
258
+ n int
259
+ c []int
260
+ }
261
+
262
+ func NewBinaryIndexedTree(n int) BinaryIndexedTree {
263
+ c := make([]int, n+1)
264
+ for i := range c {
265
+ c[i] = -inf
266
+ }
267
+ return BinaryIndexedTree{n: n, c: c}
268
+ }
269
+
270
+ func (bit *BinaryIndexedTree) update(x, v int) {
271
+ for x <= bit.n {
272
+ bit.c[x] = max(bit.c[x], v)
273
+ x += x & -x
274
+ }
275
+ }
276
+
277
+ func (bit *BinaryIndexedTree) query(x int) int {
278
+ mx := -inf
279
+ for x > 0 {
280
+ mx = max(mx, bit.c[x])
281
+ x -= x & -x
282
+ }
283
+ return mx
284
+ }
285
+
286
+ func maxBalancedSubsequenceSum(nums []int) int64 {
287
+ n := len(nums)
288
+ arr := make([]int, n)
289
+ for i, x := range nums {
290
+ arr[i] = x - i
291
+ }
292
+ sort.Ints(arr)
293
+ m := 0
294
+ for i, x := range arr {
295
+ if i == 0 || x != arr[i-1] {
296
+ arr[m] = x
297
+ m++
298
+ }
299
+ }
300
+ arr = arr[:m]
301
+ tree := NewBinaryIndexedTree(m)
302
+ for i, x := range nums {
303
+ j := sort.SearchInts(arr, x-i) + 1
304
+ v := max(tree.query(j), 0) + x
305
+ tree.update(j, v)
306
+ }
307
+ return int64(tree.query(m))
308
+ }
309
+ ```
97
310
311
+ ### ** TypeScript**
312
+
313
+ ``` ts
314
+ class BinaryIndexedTree {
315
+ private n: number ;
316
+ private c: number [];
317
+
318
+ constructor (n : number ) {
319
+ this .n = n ;
320
+ this .c = Array (n + 1 ).fill (- Infinity );
321
+ }
322
+
323
+ update(x : number , v : number ): void {
324
+ while (x <= this .n ) {
325
+ this .c [x ] = Math .max (this .c [x ], v );
326
+ x += x & - x ;
327
+ }
328
+ }
329
+
330
+ query(x : number ): number {
331
+ let mx = - Infinity ;
332
+ while (x > 0 ) {
333
+ mx = Math .max (mx , this .c [x ]);
334
+ x -= x & - x ;
335
+ }
336
+ return mx ;
337
+ }
338
+ }
339
+
340
+ function maxBalancedSubsequenceSum(nums : number []): number {
341
+ const n = nums .length ;
342
+ const arr = Array (n ).fill (0 );
343
+ for (let i = 0 ; i < n ; ++ i ) {
344
+ arr [i ] = nums [i ] - i ;
345
+ }
346
+ arr .sort ((a , b ) => a - b );
347
+ let m = 0 ;
348
+ for (let i = 0 ; i < n ; ++ i ) {
349
+ if (i === 0 || arr [i ] !== arr [i - 1 ]) {
350
+ arr [m ++ ] = arr [i ];
351
+ }
352
+ }
353
+ arr .length = m ;
354
+ const tree = new BinaryIndexedTree (m );
355
+ const search = (nums : number [], x : number ): number => {
356
+ let [l, r] = [0 , nums .length ];
357
+ while (l < r ) {
358
+ const mid = (l + r ) >> 1 ;
359
+ if (nums [mid ] >= x ) {
360
+ r = mid ;
361
+ } else {
362
+ l = mid + 1 ;
363
+ }
364
+ }
365
+ return l ;
366
+ };
367
+ for (let i = 0 ; i < n ; ++ i ) {
368
+ const j = search (arr , nums [i ] - i ) + 1 ;
369
+ const v = Math .max (tree .query (j ), 0 ) + nums [i ];
370
+ tree .update (j , v );
371
+ }
372
+ return tree .query (m );
373
+ }
98
374
```
99
375
100
376
### ** ...**
0 commit comments