Skip to content

Commit 4adca3e

Browse files
committed
第158场双周赛T1~T4 & 第453场周赛T1~T4 (8)
1 parent d731cde commit 4adca3e

16 files changed

+683
-0
lines changed
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import java.util.ArrayList;
2+
import java.util.HashMap;
3+
import java.util.List;
4+
import java.util.Map;
5+
6+
public class Solution3572 {
7+
public int maxSumDistinctTriplet(int[] x, int[] y) {
8+
int n = x.length;
9+
Map<Integer, Integer> x_maxy = new HashMap<>();
10+
for (int i = 0; i < n; i++) {
11+
int x_i = x[i];
12+
int y_i = y[i];
13+
x_maxy.merge(x_i, y_i, Math::max);
14+
}
15+
List<Integer> a = new ArrayList<>(x_maxy.values());
16+
int sz = a.size();
17+
if (sz < 3) return -1;
18+
a.sort(null);
19+
int ans = 0;
20+
for (int i = 0; i < 3; i++) {
21+
ans += a.get(sz - 1 - i);
22+
}
23+
return ans;
24+
}
25+
}
26+
/*
27+
3572. 选择不同 X 值三元组使 Y 值之和最大
28+
https://leetcode.cn/problems/maximize-ysum-by-picking-a-triplet-of-distinct-xvalues/description/
29+
30+
第 158 场双周赛 T1。
31+
32+
给你两个整数数组 x 和 y,长度均为 n。你必须选择三个 不同 的下标 i ,j 和 k,满足以下条件:
33+
- x[i] != x[j]
34+
- x[j] != x[k]
35+
- x[k] != x[i]
36+
你的目标是在满足这些条件下 最大化 y[i] + y[j] + y[k] 的值。返回通过选择这样一组三元组下标所能获得的 最大 可能和。
37+
如果不存在这样的三元组,返回 -1。
38+
提示:
39+
n == x.length == y.length
40+
3 <= n <= 10^5
41+
1 <= x[i], y[i] <= 10^6
42+
43+
贪心。
44+
*/
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import java.util.Arrays;
2+
3+
public class Solution3573 {
4+
private int[] prices;
5+
private long[][][] memo;
6+
7+
public long maximumProfit(int[] prices, int k) {
8+
this.prices = prices;
9+
int n = prices.length;
10+
memo = new long[n][k + 1][3];
11+
for (int i = 0; i < n; i++) {
12+
for (int j = 0; j < k + 1; j++) {
13+
Arrays.fill(memo[i][j], -1);
14+
}
15+
}
16+
return dfs(n - 1, k, 0);
17+
}
18+
19+
// dfs(i, 0) 表示到第 i 天结束时完成至多 j 笔交易,未持有股票的最大利润
20+
// dfs(i, 1) 表示到第 i 天结束时完成至多 j 笔交易,持有股票的最大利润
21+
// 第 i-1 天结束就是第 i 天的开始
22+
// hold 0:未持有 1:普通 2:做空
23+
private long dfs(int i, int j, int hold) {
24+
if (j < 0) return (long) -1e18;
25+
if (i < 0) {
26+
if (hold != 0) return (long) -1e18;
27+
return 0;
28+
}
29+
if (memo[i][j][hold] != -1) return memo[i][j][hold];
30+
long res;
31+
if (hold == 0) {
32+
// 什么也不干,普通交易,做空交易
33+
res = max(dfs(i - 1, j, 0), dfs(i - 1, j, 1) + prices[i], dfs(i - 1, j, 2) - prices[i]);
34+
} else if (hold == 1) {
35+
// 什么也不干,普通交易
36+
res = max(dfs(i - 1, j, 1), dfs(i - 1, j - 1, 0) - prices[i]);
37+
} else {
38+
// 什么也不干,做空交易
39+
res = max(dfs(i - 1, j, 2), dfs(i - 1, j - 1, 0) + prices[i]);
40+
}
41+
return memo[i][j][hold] = res;
42+
}
43+
44+
private long max(long... values) {
45+
long maxValue = Long.MIN_VALUE;
46+
for (long i : values) {
47+
if (i > maxValue) {
48+
maxValue = i;
49+
}
50+
}
51+
return maxValue;
52+
}
53+
}
54+
/*
55+
3573. 买卖股票的最佳时机 V
56+
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-v/description/
57+
58+
第 158 场双周赛 T2。
59+
60+
给你一个整数数组 prices,其中 prices[i] 是第 i 天股票的价格(美元),以及一个整数 k。
61+
你最多可以进行 k 笔交易,每笔交易可以是以下任一类型:
62+
- 普通交易:在第 i 天买入,然后在之后的第 j 天卖出,其中 i < j。你的利润是 prices[j] - prices[i]。
63+
- 做空交易:在第 i 天卖出,然后在之后的第 j 天买回,其中 i < j。你的利润是 prices[i] - prices[j]。
64+
注意:你必须在开始下一笔交易之前完成当前交易。此外,你不能在已经进行买入或卖出操作的同一天再次进行买入或卖出操作。
65+
通过进行 最多 k 笔交易,返回你可以获得的最大总利润。
66+
提示:
67+
2 <= prices.length <= 10^3
68+
1 <= prices[i] <= 10^9
69+
1 <= k <= prices.length / 2
70+
71+
记忆化搜索。在 188 题基础上改改即可。
72+
相似题目: 188. 买卖股票的最佳时机 IV
73+
https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/
74+
*/
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
public class Solution3574 {
2+
public long maxGCDScore(int[] nums, int k) {
3+
long ans = 0;
4+
for (int i = 0; i < nums.length; i++) {
5+
int lowbitMin = Integer.MAX_VALUE;
6+
int lowbitCnt = 0;
7+
int g = 0;
8+
for (int j = i; j >= 0; j--) {
9+
int x = nums[j];
10+
int lb = x & -x;
11+
if (lb < lowbitMin) {
12+
lowbitMin = lb;
13+
lowbitCnt = 1;
14+
} else if (lb == lowbitMin) {
15+
lowbitCnt++;
16+
}
17+
18+
g = getGCD(g, x);
19+
int newG = lowbitCnt <= k ? g * 2 : g;
20+
ans = Math.max(ans, (long) newG * (i - j + 1));
21+
}
22+
}
23+
return ans;
24+
}
25+
26+
private int getGCD(int num1, int num2) {
27+
return num1 == 0 ? num2 : getGCD(num2 % num1, num1);
28+
}
29+
}
30+
/*
31+
3574. 最大子数组 GCD 分数
32+
https://leetcode.cn/problems/maximize-subarray-gcd-score/description/
33+
34+
第 158 场双周赛 T3。
35+
36+
给你一个正整数数组 nums 和一个整数 k。
37+
你最多可以执行 k 次操作。在每次操作中,你可以选择数组中的一个元素并将其值 翻倍 。每个元素 最多 只能翻倍一次。
38+
连续 子数组 的 分数 定义为其所有元素的最大公约数 (GCD) 与子数组长度的 乘积 。
39+
你的任务是返回修改后数组中选择一个连续子数组可以获得的最大 分数 。
40+
注意:
41+
- 子数组 是数组中连续的元素序列。
42+
- 数组的 最大公约数 (GCD) 是能整除数组所有元素的最大整数。
43+
提示:
44+
1 <= n == nums.length <= 1500
45+
1 <= nums[i] <= 10^9
46+
1 <= k <= n
47+
48+
两种方法:暴力枚举 / logTrick
49+
https://leetcode.cn/problems/maximize-subarray-gcd-score/solutions/3695642/liang-chong-xie-fa-bao-li-mei-ju-logtric-zz7e/
50+
rating 2252 (clist.by)
51+
*/
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import java.util.ArrayList;
2+
import java.util.Arrays;
3+
import java.util.Collections;
4+
import java.util.HashMap;
5+
import java.util.List;
6+
import java.util.Map;
7+
8+
public class Solution3575 {
9+
private long ans = 0;
10+
11+
public int goodSubtreeSum(int[] vals, int[] par) {
12+
int n = par.length;
13+
List<Integer>[] g = new ArrayList[n];
14+
Arrays.setAll(g, i -> new ArrayList<>());
15+
for (int i = 1; i < n; i++) {
16+
g[par[i]].add(i);
17+
}
18+
19+
dfs(0, vals, g);
20+
return (int) (ans % 1_000_000_007);
21+
}
22+
23+
// 返回每种 mask 下的最大子树和
24+
private Map<Integer, Integer> dfs(int x, int[] vals, List<Integer>[] g) {
25+
Map<Integer, Integer> f = new HashMap<>();
26+
27+
// 计算 vals[x] 的数位集合 mask
28+
int mask = 0;
29+
for (int v = vals[x]; v > 0; v /= 10) {
30+
int d = v % 10;
31+
if ((mask >> d & 1) > 0) { // d 在集合 mask 中
32+
mask = 0; // 不符合要求
33+
break;
34+
}
35+
mask |= 1 << d; // 把 d 加到集合 mask 中
36+
}
37+
38+
if (mask > 0) {
39+
f.put(mask, vals[x]);
40+
}
41+
42+
for (int y : g[x]) {
43+
Map<Integer, Integer> fy = dfs(y, vals, g);
44+
Map<Integer, Integer> nf = new HashMap<>(f);
45+
for (Map.Entry<Integer, Integer> e : fy.entrySet()) {
46+
int msk = e.getKey();
47+
int s = e.getValue();
48+
// 同一个 mask 至多选一个,直接取 max
49+
nf.merge(msk, s, Math::max);
50+
// 求两个 mask 的并集,刷表转移
51+
for (Map.Entry<Integer, Integer> e2 : f.entrySet()) {
52+
int msk2 = e2.getKey();
53+
if ((msk & msk2) == 0) {
54+
nf.merge(msk | msk2, s + e2.getValue(), Math::max);
55+
}
56+
}
57+
}
58+
f = nf;
59+
}
60+
61+
if (!f.isEmpty()) {
62+
ans += Collections.max(f.values());
63+
}
64+
65+
return f;
66+
}
67+
}
68+
/*
69+
3575. 最大好子树分数
70+
https://leetcode.cn/problems/maximum-good-subtree-score/description/
71+
72+
第 158 场双周赛 T4。
73+
74+
给你一个根节点为 0 的无向树,包含 n 个节点,编号从 0 到 n - 1。每个节点 i 都有一个整数值 vals[i],其父节点为 par[i] 。
75+
从一个节点 子树 内选取部分节点,它们的数值组成一个 子集 ,如果所选数值的十进制表示中,从 0 到 9 每个数字在所有数的数位最多出现一次,那么我们称它是 好 子集。
76+
一个好子集的 分数 是其节点值的总和。
77+
定义一个长度为 n 的数组 maxScore,其中 maxScore[u] 表示以节点 u 为根的子树(包括 u 本身及其所有后代)中,好子集的最大可能值总和。
78+
返回 maxScore 中所有值的总和。
79+
由于答案可能很大,请将其对 10^9 + 7 取模 后返回。
80+
数组的 子集 是选取数组中元素得到的集合(可能为空)。
81+
提示:
82+
1 <= n == vals.length <= 500
83+
1 <= vals[i] <= 10^9
84+
par.length == n
85+
par[0] == -1
86+
对于 [1, n - 1] 中的每一个 i ,都有 0 <= par[i] < n 。
87+
输入生成保证父数组 par 表示一棵有效的树。
88+
89+
树形 DP + 状态压缩 + 启发式合并
90+
https://leetcode.cn/problems/maximum-good-subtree-score/solutions/3695614/shu-xing-dp-mei-ju-zi-ji-by-endlesscheng-e2je/
91+
rating 2350 (clist.by)
92+
*/
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import java.util.ArrayList;
2+
import java.util.List;
3+
4+
public class Solution3576 {
5+
public boolean canMakeEqual(int[] nums, int k) {
6+
int n = nums.length;
7+
List<Integer> pos0 = new ArrayList<>();
8+
List<Integer> pos1 = new ArrayList<>();
9+
for (int i = 0; i < n; i++) {
10+
if (nums[i] == -1) pos0.add(i);
11+
else pos1.add(i);
12+
}
13+
return check(k, pos0) || check(k, pos1);
14+
}
15+
16+
private boolean check(int k, List<Integer> pos) {
17+
int sz = pos.size();
18+
if (sz % 2 != 0) return false;
19+
for (int i = 0; i < sz; i += 2) {
20+
k -= pos.get(i + 1) - pos.get(i);
21+
if (k < 0) return false;
22+
}
23+
return true;
24+
}
25+
}
26+
/*
27+
3576. 数组元素相等转换
28+
https://leetcode.cn/problems/transform-array-to-all-equal-elements/description/
29+
30+
第 453 场周赛 T1。
31+
32+
给你一个大小为 n 的整数数组 nums,其中只包含 1 和 -1,以及一个整数 k。
33+
你可以最多进行 k 次以下操作:
34+
选择一个下标 i(0 <= i < n - 1),然后将 nums[i] 和 nums[i + 1] 同时 乘以 -1。
35+
注意:你可以在 不同 的操作中多次选择相同的下标 i。
36+
如果在最多 k 次操作后可以使数组的所有元素相等,则返回 true;否则,返回 false。
37+
提示:
38+
1 <= n == nums.length <= 10^5
39+
nums[i] 的值为 -1 或 1。
40+
1 <= k <= n
41+
42+
分类讨论,两种情况:都变成 1 或者都变成 -1
43+
*/
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
public class Solution3577 {
2+
private static final int MOD = (int) (1e9 + 7);
3+
4+
public int countPermutations(int[] complexity) {
5+
int n = complexity.length;
6+
int minVal = complexity[0];
7+
long ans = 1;
8+
for (int i = 1; i < n; i++) {
9+
if (minVal >= complexity[i]) {
10+
return 0;
11+
}
12+
ans = (ans * i) % MOD;
13+
}
14+
return (int) ans;
15+
}
16+
}
17+
/*
18+
3577. 统计计算机解锁顺序排列数
19+
https://leetcode.cn/problems/count-the-number-of-computer-unlocking-permutations/description/
20+
21+
第 453 场周赛 T2。
22+
23+
给你一个长度为 n 的数组 complexity。
24+
在房间里有 n 台 上锁的 计算机,这些计算机的编号为 0 到 n - 1,每台计算机都有一个 唯一 的密码。编号为 i 的计算机的密码复杂度为 complexity[i]。
25+
编号为 0 的计算机密码已经 解锁 ,并作为根节点。其他所有计算机必须通过它或其他已经解锁的计算机来解锁,具体规则如下:
26+
可以使用编号为 j 的计算机的密码解锁编号为 i 的计算机,其中 j 是任何小于 i 的整数,且满足 complexity[j] < complexity[i](即 j < i 并且 complexity[j] < complexity[i])。
27+
要解锁编号为 i 的计算机,你需要事先解锁一个编号为 j 的计算机,满足 j < i 并且 complexity[j] < complexity[i]。
28+
求共有多少种 [0, 1, 2, ..., (n - 1)] 的排列方式,能够表示从编号为 0 的计算机(唯一初始解锁的计算机)开始解锁所有计算机的有效顺序。
29+
由于答案可能很大,返回结果需要对 10^9 + 7 取余数。
30+
注意:编号为 0 的计算机的密码已解锁,而 不是 排列中第一个位置的计算机密码已解锁。
31+
排列 是一个数组中所有元素的重新排列。
32+
提示:
33+
2 <= complexity.length <= 10^5
34+
1 <= complexity[i] <= 10^9
35+
36+
脑筋急转弯。
37+
*/

0 commit comments

Comments
 (0)