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 3703361

Browse files
committed
第150场双周赛T1~T4 & 第437场周赛T1~T4 (8)
1 parent 4c5231a commit 3703361

16 files changed

+892
-0
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
public class Solution3452 {
2+
public int sumOfGoodNumbers(int[] nums, int k) {
3+
int n = nums.length;
4+
int ans = 0;
5+
for (int i = 0; i < n; i++) {
6+
if (i - k >= 0 && nums[i] <= nums[i - k] ||
7+
i + k < n && nums[i] <= nums[i + k]) {
8+
continue;
9+
}
10+
ans += nums[i];
11+
}
12+
return ans;
13+
}
14+
}
15+
/*
16+
3452. 好数字之和
17+
https://leetcode.cn/problems/sum-of-good-numbers/description/
18+
19+
第 150 场双周赛 T1。
20+
21+
给定一个整数数组 nums 和一个整数 k,如果元素 nums[i] 严格 大于下标 i - k 和 i + k 处的元素(如果这些元素存在),则该元素 nums[i] 被认为是 好 的。如果这两个下标都不存在,那么 nums[i] 仍然被认为是 好 的。
22+
返回数组中所有 好 元素的 和。
23+
提示:
24+
2 <= nums.length <= 100
25+
1 <= nums[i] <= 1000
26+
1 <= k <= floor(nums.length / 2)
27+
28+
遍历。
29+
时间复杂度 O(n)。
30+
*/
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
import java.util.TreeMap;
2+
3+
public class Solution3453 {
4+
// 浮点数二分
5+
static class V1 {
6+
public double separateSquares(int[][] squares) {
7+
long totArea = 0;
8+
int maxY = 0;
9+
for (int[] sq : squares) {
10+
int l = sq[2];
11+
totArea += (long) l * l;
12+
maxY = Math.max(maxY, sq[1] + l);
13+
}
14+
15+
double left = 0;
16+
double right = maxY;
17+
for (int i = 0; i < 47; i++) {
18+
double mid = (left + right) / 2;
19+
if (check(squares, mid, totArea)) {
20+
right = mid;
21+
} else {
22+
left = mid;
23+
}
24+
}
25+
return (left + right) / 2; // 区间中点误差小
26+
}
27+
28+
private boolean check(int[][] squares, double y, long totArea) {
29+
double area = 0;
30+
for (int[] sq : squares) {
31+
double yi = sq[1];
32+
if (yi < y) {
33+
double l = sq[2];
34+
area += l * Math.min(y - yi, l);
35+
}
36+
}
37+
return area >= totArea / 2.0;
38+
}
39+
}
40+
41+
static class V2 {
42+
// 整数二分(二分整数 y * M)
43+
// private static final int M = 100_000;
44+
//
45+
// public double separateSquares(int[][] squares) {
46+
// long totArea = 0;
47+
// int maxY = 0;
48+
// for (int[] sq : squares) {
49+
// int l = sq[2];
50+
// totArea += (long) l * l;
51+
// maxY = Math.max(maxY, sq[1] + l);
52+
// }
53+
//
54+
// long left = 0;
55+
// long right = (long) maxY * M;
56+
// while (left + 1 < right) {
57+
// long mid = (left + right) >>> 1;
58+
// if (check(squares, mid, totArea)) {
59+
// right = mid;
60+
// } else {
61+
// left = mid;
62+
// }
63+
// }
64+
// return (double) right / M;
65+
// }
66+
//
67+
// private boolean check(int[][] squares, long multiY, double totArea) {
68+
// long area = 0;
69+
// for (int[] sq : squares) {
70+
// long y = sq[1];
71+
// if (y * M < multiY) {
72+
// long l = sq[2];
73+
// area += l * Math.min(multiY - y * M, l * M);
74+
// }
75+
// }
76+
// return area * 2 >= totArea * M;
77+
// }
78+
79+
// 整数二分(二分最小的整数 y),浮点数部分通过解方程
80+
public double separateSquares(int[][] squares) {
81+
long totArea = 0;
82+
int maxY = 0;
83+
for (int[] sq : squares) {
84+
int l = sq[2];
85+
totArea += (long) l * l;
86+
maxY = Math.max(maxY, sq[1] + l);
87+
}
88+
89+
int left = 0;
90+
int right = maxY;
91+
while (left + 1 < right) {
92+
int mid = (left + right) >>> 1;
93+
if (calcArea(squares, mid) * 2 >= totArea) {
94+
right = mid;
95+
} else {
96+
left = mid;
97+
}
98+
}
99+
int y = right;
100+
101+
long areaY = calcArea(squares, y);
102+
long sumL = areaY - calcArea(squares, y - 1);
103+
return y - (areaY * 2 - totArea) / (sumL * 2.0); // 这样写误差更小
104+
}
105+
106+
private long calcArea(int[][] squares, int y) {
107+
long area = 0;
108+
for (int[] sq : squares) {
109+
int yi = sq[1];
110+
if (yi < y) {
111+
int l = sq[2];
112+
area += (long) l * Math.min(y - yi, l);
113+
}
114+
}
115+
return area;
116+
}
117+
}
118+
119+
// 差分
120+
static class V3 {
121+
public double separateSquares(int[][] squares) {
122+
long totArea = 0;
123+
TreeMap<Integer, Long> diff = new TreeMap<>();
124+
for (int[] sq : squares) {
125+
int y = sq[1];
126+
long l = sq[2];
127+
totArea += l * l;
128+
diff.merge(y, l, Long::sum);
129+
diff.merge(y + (int) l, -l, Long::sum);
130+
}
131+
132+
long area = 0;
133+
long sumL = 0;
134+
int preY = 0; // 不好计算下一个 y,改成维护上一个 y
135+
for (var e : diff.entrySet()) {
136+
int y = e.getKey();
137+
area += sumL * (y - preY); // 底边长 * 高 = 新增面积
138+
if (area * 2 >= totArea) {
139+
return y - (area * 2 - totArea) / (sumL * 2.0);
140+
}
141+
preY = y;
142+
sumL += e.getValue(); // 矩形底边长度之和
143+
}
144+
return -1;
145+
}
146+
}
147+
}
148+
/*
149+
3453. 分割正方形 I
150+
https://leetcode.cn/problems/separate-squares-i/description/
151+
152+
第 150 场双周赛 T2。
153+
154+
给你一个二维整数数组 squares ,其中 squares[i] = [xi, yi, li] 表示一个与 x 轴平行的正方形的左下角坐标和正方形的边长。
155+
找到一个最小的 y 坐标,它对应一条水平线,该线需要满足它以上正方形的总面积 等于 该线以下正方形的总面积。
156+
答案如果与实际答案的误差在 10^-5 以内,将视为正确答案。
157+
注意:正方形 可能会 重叠。重叠区域应该被 多次计数 。
158+
提示:
159+
1 <= squares.length <= 5 * 10^4
160+
squares[i] = [xi, yi, li]
161+
squares[i].length == 3
162+
0 <= xi, yi <= 10^9
163+
1 <= li <= 10^9
164+
所有正方形的总面积不超过 10^12。
165+
166+
浮点数二分 / 整数二分 / 差分。
167+
由于浮点数精度问题,赛后增加了 所有正方形的总面积不超过 10^12 条件。
168+
*/
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
import java.util.ArrayList;
2+
import java.util.Arrays;
3+
import java.util.List;
4+
import java.util.Map;
5+
import java.util.TreeMap;
6+
7+
public class Solution3454 {
8+
// 线段树模板,只需要实现 mergeInfo 和 _do,其余都是固定的
9+
static class LazySegmentTree {
10+
static class Info {
11+
// mn:当前节点的最小覆盖数
12+
// len:满足覆盖数 = 最小覆盖数的 A[i] 之和
13+
// lazy:加法的懒标记
14+
int mn, len, lazy;
15+
16+
public Info(int mn, int len, int lazy) {
17+
this.mn = mn;
18+
this.len = len;
19+
this.lazy = lazy;
20+
}
21+
}
22+
23+
Info mergeInfo(Info a, Info b) {
24+
int mn = Math.min(a.mn, b.mn);
25+
return new Info(mn, (a.mn == mn ? a.len : 0) + (b.mn == mn ? b.len : 0), 0);
26+
}
27+
28+
// 对节点的覆盖数整个增加 qv,只影响 mn,不影响 len
29+
void _do(int p, int qv) {
30+
info[p].mn += qv;
31+
info[p].lazy += qv;
32+
}
33+
34+
int n;
35+
Info[] info;
36+
37+
public LazySegmentTree(int n) {
38+
this.n = n;
39+
info = new Info[4 * n];
40+
}
41+
42+
void build(int[] A, int p, int l, int r) {
43+
if (l == r) {
44+
info[p] = new Info(0, A[r] - A[r - 1], 0);
45+
return;
46+
}
47+
int m = (l + r) >> 1;
48+
build(A, p << 1, l, m);
49+
build(A, p << 1 | 1, m + 1, r);
50+
maintain(p);
51+
}
52+
53+
void maintain(int p) {
54+
info[p] = mergeInfo(info[p << 1], info[p << 1 | 1]);
55+
}
56+
57+
void spread(int p) {
58+
if (info[p].lazy == 0) return;
59+
_do(p << 1, info[p].lazy);
60+
_do(p << 1 | 1, info[p].lazy);
61+
info[p].lazy = 0;
62+
}
63+
64+
void modify(int p, int l, int r, int ql, int qr, int qv) {
65+
if (ql <= l && r <= qr) {
66+
_do(p, qv);
67+
return;
68+
}
69+
spread(p);
70+
int m = (l + r) >> 1;
71+
if (ql <= m) modify(p << 1, l, m, ql, qr, qv);
72+
if (qr > m) modify(p << 1 | 1, m + 1, r, ql, qr, qv);
73+
maintain(p);
74+
}
75+
}
76+
77+
public double separateSquares(int[][] squares) {
78+
int m = 0;
79+
TreeMap<Integer, Integer> mp = new TreeMap<>();
80+
for (int[] sq : squares) {
81+
mp.put(sq[0], 1);
82+
mp.put(sq[0] + sq[2], 1);
83+
}
84+
for (Map.Entry<Integer, Integer> p : mp.entrySet()) p.setValue(m++);
85+
int[] A = new int[m];
86+
for (Map.Entry<Integer, Integer> p : mp.entrySet()) A[p.getValue()] = p.getKey();
87+
// 离散化结束
88+
89+
// 把正方形的上下边界取出来
90+
List<int[]> vec = new ArrayList<>();
91+
for (int[] sq : squares) {
92+
vec.add(new int[]{sq[1], mp.get(sq[0]) + 1, mp.get(sq[0] + sq[2]), 1});
93+
vec.add(new int[]{sq[1] + sq[2], mp.get(sq[0]) + 1, mp.get(sq[0] + sq[2]), -1});
94+
}
95+
vec.sort(Arrays::compare);
96+
97+
// 求总的面积并
98+
long tot = 0;
99+
LazySegmentTree seg = new LazySegmentTree(m);
100+
seg.build(A, 1, 1, m - 1);
101+
for (int i = 0; i + 1 < vec.size(); i++) {
102+
// 考虑水平线 y = vec[i][0] 和 y = vec[i + 1][0] 之间的情况
103+
seg.modify(1, 1, m - 1, vec.get(i)[1], vec.get(i)[2], vec.get(i)[3]);
104+
// 求横截长度
105+
int len = A[m - 1] - A[0];
106+
// 如果最小覆盖数是 0,那么扣掉相应的长度
107+
if (seg.info[1].mn == 0) len -= seg.info[1].len;
108+
// 面积 = 横截长度 * 高度差
109+
tot += (long) len * (vec.get(i + 1)[0] - vec.get(i)[0]);
110+
}
111+
112+
long now = 0;
113+
seg.build(A, 1, 1, m - 1);
114+
for (int i = 0; i + 1 < vec.size(); i++) {
115+
seg.modify(1, 1, m - 1, vec.get(i)[1], vec.get(i)[2], vec.get(i)[3]);
116+
int len = A[m - 1] - A[0];
117+
if (seg.info[1].mn == 0) len -= seg.info[1].len;
118+
now += (long) len * (vec.get(i + 1)[0] - vec.get(i)[0]);
119+
// delta 非负了,套公式
120+
long det = now - (tot - now);
121+
if (det >= 0) return vec.get(i + 1)[0] - 0.5 * det / len;
122+
}
123+
return -1;
124+
}
125+
}
126+
/*
127+
3454. 分割正方形 II
128+
https://leetcode.cn/problems/separate-squares-ii/description/
129+
130+
第 150 场双周赛 T3。
131+
132+
给你一个二维整数数组 squares ,其中 squares[i] = [xi, yi, li] 表示一个与 x 轴平行的正方形的左下角坐标和正方形的边长。
133+
找到一个最小的 y 坐标,它对应一条水平线,该线需要满足它以上正方形的总面积 等于 该线以下正方形的总面积。
134+
答案如果与实际答案的误差在 10^-5 以内,将视为正确答案。
135+
注意:正方形 可能会 重叠。重叠区域只 统计一次 。
136+
提示:
137+
1 <= squares.length <= 5 * 10^4
138+
squares[i] = [xi, yi, li]
139+
squares[i].length == 3
140+
0 <= xi, yi <= 10^9
141+
1 <= li <= 10^9
142+
所有正方形的总面积不超过 10^15。
143+
144+
Lazy 线段树 + 扫描线
145+
https://leetcode.cn/problems/separate-squares-ii/solutions/3076772/sao-miao-xian-xian-duan-shu-xiang-jie-ju-d7oj/
146+
相似题目: 850. 矩形面积 II
147+
https://leetcode.cn/problems/rectangle-area-ii/description/
148+
rating 2614 (clist.by)
149+
*/

0 commit comments

Comments
(0)

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