Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit c877abf

Browse files
committed
第452场周赛T1~T4 (4)
1 parent ba018f2 commit c877abf

File tree

8 files changed

+458
-0
lines changed

8 files changed

+458
-0
lines changed
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
public class Solution3566 {
2+
public boolean checkEqualPartitions(int[] nums, long target) {
3+
int n = nums.length;
4+
for (int msk = 0; msk < 1 << (n - 1); msk++) {
5+
long prod1 = 1;
6+
long prod2 = 1;
7+
for (int i = 0; i < n; i++) {
8+
if ((msk & (1 << i)) != 0) {
9+
prod1 *= nums[i];
10+
} else {
11+
prod2 *= nums[i];
12+
}
13+
if (prod1 > target || prod2 > target) break;
14+
}
15+
if (prod1 == prod2 && prod1 == target) return true;
16+
}
17+
return false;
18+
}
19+
}
20+
/*
21+
3566. 等积子集的划分方案
22+
https://leetcode.cn/problems/partition-array-into-two-equal-product-subsets/description/
23+
24+
第 452 场周赛 T1。
25+
26+
给你一个整数数组 nums,其中包含的正整数 互不相同 ,另给你一个整数 target。
27+
请判断是否可以将 nums 分成两个 非空、互不相交 的 子集 ,并且每个元素必须 恰好 属于 一个 子集,使得这两个子集中元素的乘积都等于 target。
28+
如果存在这样的划分,返回 true;否则,返回 false。
29+
子集 是数组中元素的一个选择集合。
30+
提示:
31+
3 <= nums.length <= 12
32+
1 <= target <= 10^15
33+
1 <= nums[i] <= 100
34+
nums 中的所有元素互不相同。
35+
36+
二进制枚举。
37+
时间复杂度 O(n * 2^n)。
38+
*/
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import java.util.Arrays;
2+
3+
public class Solution3567 {
4+
public int[][] minAbsDiff(int[][] grid, int k) {
5+
int m = grid.length;
6+
int n = grid[0].length;
7+
int[][] ans = new int[m - k + 1][n - k + 1];
8+
int[] a = new int[k * k];
9+
for (int i = 0; i + k - 1 < m; i++) {
10+
for (int j = 0; j + k - 1 < n; j++) {
11+
int idx = 0;
12+
for (int x = 0; x < k; x++) {
13+
for (int y = 0; y < k; y++) {
14+
a[idx++] = grid[i + x][j + y];
15+
}
16+
}
17+
Arrays.sort(a);
18+
19+
int mn = Integer.MAX_VALUE;
20+
for (int i0 = 1; i0 < k * k; i0++) {
21+
if (a[i0] != a[i0 - 1]) { // 不同值
22+
mn = Math.min(mn, a[i0] - a[i0 - 1]);
23+
}
24+
}
25+
if (mn == Integer.MAX_VALUE) continue;
26+
ans[i][j] = mn;
27+
}
28+
}
29+
return ans;
30+
}
31+
}
32+
/*
33+
3567. 子矩阵的最小绝对差
34+
https://leetcode.cn/problems/minimum-absolute-difference-in-sliding-submatrix/description/
35+
36+
第 452 场周赛 T2。
37+
38+
给你一个 m x n 的整数矩阵 grid 和一个整数 k。
39+
对于矩阵 grid 中的每个连续的 k x k 子矩阵,计算其中任意两个 不同值 之间的 最小绝对差 。
40+
返回一个大小为 (m - k + 1) x (n - k + 1) 的二维数组 ans,其中 ans[i][j] 表示以 grid 中坐标 (i, j) 为左上角的子矩阵的最小绝对差。
41+
注意:如果子矩阵中的所有元素都相同,则答案为 0。
42+
子矩阵 (x1, y1, x2, y2) 是一个由选择矩阵中所有满足 x1 <= x <= x2 且 y1 <= y <= y2 的单元格 matrix[x][y] 组成的矩阵。
43+
提示:
44+
1 <= m == grid.length <= 30
45+
1 <= n == grid[i].length <= 30
46+
-10^5 <= grid[i][j] <= 10^5
47+
1 <= k <= min(m, n)
48+
49+
暴力枚举。
50+
把 a 排序后,不同元素之差的最小值一定在相邻元素中,计算相邻不同元素之差的最小值。
51+
时间复杂度 O((m-k)*(n-k) * k^2 logk)。
52+
*/
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import java.util.ArrayList;
2+
import java.util.List;
3+
4+
public class Solution3568 {
5+
private static final int[][] DIRECTIONS = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
6+
7+
private record Node(int x, int y, int e, int mask) {
8+
}
9+
10+
public int minMoves(String[] classroom, int energy) {
11+
int m = classroom.length;
12+
int n = classroom[0].length();
13+
14+
int[][] idx = new int[m][n];
15+
int cntL = 0, sx = 0, sy = 0;
16+
for (int i = 0; i < m; i++) {
17+
String row = classroom[i];
18+
for (int j = 0; j < n; j++) {
19+
char b = row.charAt(j);
20+
if (b == 'L') {
21+
idx[i][j] = cntL++; // 给垃圾分配编号
22+
} else if (b == 'S') {
23+
sx = i;
24+
sy = j;
25+
}
26+
}
27+
}
28+
29+
int full = (1 << cntL) - 1;
30+
boolean[][][][] vis = new boolean[m][n][energy + 1][full + 1];
31+
vis[sx][sy][energy][0] = true;
32+
33+
List<Node> q = new ArrayList<>();
34+
q.add(new Node(sx, sy, energy, 0));
35+
for (int ans = 0; !q.isEmpty(); ans++) {
36+
List<Node> tmp = q;
37+
q = new ArrayList<>();
38+
for (Node p : tmp) {
39+
if (p.mask == full) { // 所有垃圾清理完毕
40+
return ans;
41+
}
42+
if (p.e == 0) { // 走不动了
43+
continue;
44+
}
45+
for (int[] d : DIRECTIONS) {
46+
int x = p.x + d[0], y = p.y + d[1];
47+
if (x >= 0 && x < m && y >= 0 && y < n && classroom[x].charAt(y) != 'X') {
48+
int newE = classroom[x].charAt(y) == 'R' ? energy : p.e - 1;
49+
int newMask = classroom[x].charAt(y) == 'L' ? p.mask | (1 << idx[x][y]) : p.mask;
50+
if (!vis[x][y][newE][newMask]) {
51+
vis[x][y][newE][newMask] = true;
52+
q.add(new Node(x, y, newE, newMask));
53+
}
54+
}
55+
}
56+
}
57+
}
58+
return -1;
59+
}
60+
}
61+
/*
62+
3568. 清理教室的最少移动
63+
https://leetcode.cn/problems/minimum-moves-to-clean-the-classroom/description/
64+
65+
第 452 场周赛 T3。
66+
67+
给你一个 m x n 的网格图 classroom,其中一个学生志愿者负责清理散布在教室里的垃圾。网格图中的每个单元格是以下字符之一:
68+
- 'S' :学生的起始位置
69+
- 'L' :必须收集的垃圾(收集后,该单元格变为空白)
70+
- 'R' :重置区域,可以将学生的能量恢复到最大值,无论学生当前的能量是多少(可以多次使用)
71+
- 'X' :学生无法通过的障碍物
72+
- '.' :空白空间
73+
同时给你一个整数 energy,表示学生的最大能量容量。学生从起始位置 'S' 开始,带着 energy 的能量出发。
74+
每次移动到相邻的单元格(上、下、左或右)会消耗 1 单位能量。如果能量为 0,学生此时只有处在 'R' 格子时可以继续移动,此区域会将能量恢复到 最大 能量值 energy。
75+
返回收集所有垃圾所需的 最少 移动次数,如果无法完成,返回 -1。
76+
提示:
77+
1 <= m == classroom.length <= 20
78+
1 <= n == classroom[i].length <= 20
79+
classroom[i][j] 是 'S'、'L'、'R'、'X' 或 '.' 之一
80+
1 <= energy <= 50
81+
网格图中恰好有 一个 'S'。
82+
网格图中 最多 有 10 个 'L' 单元格。
83+
84+
BFS + 优化。
85+
https://leetcode.cn/problems/minimum-moves-to-clean-the-classroom/solutions/3690747/bfs-by-endlesscheng-rpk6/
86+
*/
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
import java.util.Arrays;
2+
import java.util.HashMap;
3+
import java.util.Map;
4+
import java.util.TreeSet;
5+
6+
public class Solution3569 {
7+
static final int MAX_N = (int) 1e5;
8+
static boolean[] np;
9+
10+
static {
11+
np = new boolean[MAX_N + 1];
12+
np[1] = true;
13+
for (int i = 2; i * i <= MAX_N; i++) {
14+
if (!np[i]) {
15+
for (int j = i * i; j <= MAX_N; j += i) {
16+
np[j] = true;
17+
}
18+
}
19+
}
20+
}
21+
22+
public int[] maximumCount(int[] nums, int[][] queries) {
23+
int n = nums.length;
24+
Map<Integer, TreeSet<Integer>> pos = new HashMap<>();
25+
for (int i = 0; i < n; i++) {
26+
int x = nums[i];
27+
if (!np[x]) {
28+
pos.computeIfAbsent(x, k -> new TreeSet<>()).add(i);
29+
}
30+
}
31+
32+
LazyInfoSegmentTree seg = new LazyInfoSegmentTree(n);
33+
// seg.build(new int[n], 1, 0, n - 1);
34+
for (TreeSet<Integer> s : pos.values()) {
35+
if (s.size() > 1) {
36+
seg.modify(1, 0, n - 1, s.first(), s.last(), 1);
37+
}
38+
}
39+
40+
int[] ans = new int[queries.length];
41+
for (int qi = 0; qi < queries.length; qi++) {
42+
int[] q = queries[qi];
43+
int i = q[0];
44+
int v = q[1];
45+
int old = nums[i];
46+
nums[i] = v;
47+
48+
// 处理旧值
49+
if (!np[old]) {
50+
TreeSet<Integer> s = pos.get(old);
51+
if (s.size() > 1) {
52+
seg.modify(1, 0, n - 1, s.first(), s.last(), -1);
53+
}
54+
s.remove(i);
55+
if (s.size() > 1) {
56+
seg.modify(1, 0, n - 1, s.first(), s.last(), 1);
57+
} else if (s.isEmpty()) {
58+
pos.remove(old);
59+
}
60+
}
61+
62+
// 处理新值
63+
if (!np[v]) {
64+
TreeSet<Integer> s = pos.computeIfAbsent(v, k -> new TreeSet<>());
65+
if (s.size() > 1) {
66+
seg.modify(1, 0, n - 1, s.first(), s.last(), -1);
67+
}
68+
s.add(i);
69+
if (s.size() > 1) {
70+
seg.modify(1, 0, n - 1, s.first(), s.last(), 1);
71+
}
72+
}
73+
74+
// 整个数组的不同质数个数 + 切一刀的最大额外收益
75+
ans[qi] = pos.size() + seg.query(1, 0, n - 1, 0, n - 1).mx;
76+
}
77+
return ans;
78+
}
79+
80+
// 线段树模板,只需要实现 mergeInfo 和 _do,其余都是固定的
81+
static class LazyInfoSegmentTree {
82+
static class Info {
83+
int mx, lazy; // 区间加一、区间最大值
84+
85+
public Info(int mx, int lazy) {
86+
this.mx = mx;
87+
this.lazy = lazy;
88+
}
89+
}
90+
91+
Info mergeInfo(Info a, Info b) {
92+
int mx = Math.max(a.mx, b.mx);
93+
return new Info(mx, 0);
94+
}
95+
96+
void _do(int p, int qv) {
97+
info[p].mx += qv;
98+
info[p].lazy += qv;
99+
}
100+
101+
int n;
102+
Info[] info;
103+
104+
public LazyInfoSegmentTree(int n) {
105+
this.n = n;
106+
info = new Info[4 * n];
107+
Arrays.setAll(info, e -> new Info(0, 0));
108+
}
109+
110+
void build(int[] A, int p, int l, int r) {
111+
if (l == r) {
112+
info[p] = new Info(0, 0);
113+
return;
114+
}
115+
int m = (l + r) >> 1;
116+
build(A, p << 1, l, m);
117+
build(A, p << 1 | 1, m + 1, r);
118+
maintain(p);
119+
}
120+
121+
void maintain(int p) {
122+
info[p] = mergeInfo(info[p << 1], info[p << 1 | 1]);
123+
}
124+
125+
void spread(int p) {
126+
if (info[p].lazy == 0) return;
127+
_do(p << 1, info[p].lazy);
128+
_do(p << 1 | 1, info[p].lazy);
129+
info[p].lazy = 0;
130+
}
131+
132+
void modify(int p, int l, int r, int ql, int qr, int qv) {
133+
if (ql <= l && r <= qr) {
134+
_do(p, qv);
135+
return;
136+
}
137+
spread(p);
138+
int m = (l + r) >> 1;
139+
if (ql <= m) modify(p << 1, l, m, ql, qr, qv);
140+
if (qr > m) modify(p << 1 | 1, m + 1, r, ql, qr, qv);
141+
maintain(p);
142+
}
143+
144+
Info query(int p, int l, int r, int ql, int qr) {
145+
if (ql <= l && r <= qr) {
146+
return info[p];
147+
}
148+
spread(p);
149+
int m = (l + r) >> 1;
150+
if (qr <= m) return query(p << 1, l, m, ql, qr);
151+
if (ql > m) return query(p << 1 | 1, m + 1, r, ql, qr);
152+
return mergeInfo(query(p << 1, l, m, ql, qr), query(p << 1 | 1, m + 1, r, ql, qr));
153+
}
154+
}
155+
}
156+
/*
157+
3569. 分割数组后不同质数的最大数目
158+
https://leetcode.cn/problems/maximize-count-of-distinct-primes-after-split/description/
159+
160+
第 452 场周赛 T4。
161+
162+
给你一个长度为 'n' 的整数数组 nums,以及一个二维整数数组 queries,其中 queries[i] = [idx, val]。
163+
对于每个查询:
164+
1.更新 nums[idx] = val。
165+
2.选择一个满足 1 <= k < n 的整数 k ,将数组分为非空前缀 nums[0..k-1] 和后缀 nums[k..n-1],使得每部分中 不同 质数的数量之和 最大 。
166+
注意:每次查询对数组的更改将持续到后续的查询中。
167+
返回一个数组,包含每个查询的结果,按给定的顺序排列。
168+
质数是大于 1 的自然数,只有 1 和它本身两个因数。
169+
提示:
170+
2 <= n == nums.length <= 5 * 10^4
171+
1 <= queries.length <= 5 * 10^4
172+
1 <= nums[i] <= 10^5
173+
0 <= queries[i][0] < nums.length
174+
1 <= queries[i][1] <= 10^5
175+
176+
Lazy 线段树 + 有序集合
177+
https://leetcode.cn/problems/maximize-count-of-distinct-primes-after-split/solutions/3690759/xian-duan-shu-you-xu-ji-he-by-endlessche-j3nm/
178+
转化非常巧妙!!
179+
rating 2543 (clist.by)
180+
*/
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import org.junit.jupiter.api.Assertions;
2+
import org.junit.jupiter.api.Test;
3+
4+
public class Solution3566Tests {
5+
private final Solution3566 solution3566 = new Solution3566();
6+
7+
@Test
8+
public void example1() {
9+
int[] nums = {3, 1, 6, 8, 4};
10+
long target = 24;
11+
Assertions.assertTrue(solution3566.checkEqualPartitions(nums, target));
12+
}
13+
14+
@Test
15+
public void example2() {
16+
int[] nums = {2, 5, 3, 7};
17+
long target = 15;
18+
Assertions.assertFalse(solution3566.checkEqualPartitions(nums, target));
19+
}
20+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /