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 06a9033

Browse files
committed
第444场周赛T1~T4 (4)
1 parent 699db72 commit 06a9033

File tree

8 files changed

+657
-0
lines changed

8 files changed

+657
-0
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
public class Solution3507 {
2+
}
3+
/*
4+
3507. 移除最小数对使数组有序 I
5+
https://leetcode.cn/problems/minimum-pair-removal-to-sort-array-i/description/
6+
7+
第 444 场周赛 T1。
8+
9+
给你一个数组 nums,你可以执行以下操作任意次数:
10+
- 选择 相邻 元素对中 和最小 的一对。如果存在多个这样的对,选择最左边的一个。
11+
- 用它们的和替换这对元素。
12+
返回将数组变为 非递减 所需的 最小操作次数 。
13+
如果一个数组中每个元素都大于或等于它前一个元素(如果存在的话),则称该数组为非递减。
14+
提示:
15+
1 <= nums.length <= 50
16+
-1000 <= nums[i] <= 1000
17+
18+
同: 3510. 移除最小数对使数组有序 II
19+
https://leetcode.cn/problems/minimum-pair-removal-to-sort-array-ii/description/
20+
*/
Lines changed: 231 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,231 @@
1+
import java.util.ArrayDeque;
2+
import java.util.ArrayList;
3+
import java.util.HashMap;
4+
import java.util.HashSet;
5+
import java.util.List;
6+
import java.util.Map;
7+
import java.util.Queue;
8+
import java.util.Set;
9+
10+
public class Solution3508 {
11+
// 队列上二分
12+
static class Router {
13+
record Packet(int source, int destination, int timestamp) {
14+
}
15+
16+
int memoryLimit;
17+
Queue<Packet> packetQueue;
18+
Set<Packet> packetSet;
19+
Map<Integer, List<Integer>> destinationMap;
20+
21+
public Router(int memoryLimit) {
22+
this.memoryLimit = memoryLimit;
23+
this.packetQueue = new ArrayDeque<>();
24+
this.packetSet = new HashSet<>();
25+
this.destinationMap = new HashMap<>();
26+
}
27+
28+
public boolean addPacket(int source, int destination, int timestamp) {
29+
Packet newPacket = new Packet(source, destination, timestamp);
30+
if (packetSet.contains(newPacket)) {
31+
return false;
32+
}
33+
if (packetQueue.size() >= memoryLimit) {
34+
forwardPacket();
35+
}
36+
packetQueue.add(newPacket);
37+
packetSet.add(newPacket);
38+
39+
List<Integer> destTsMap = destinationMap.computeIfAbsent(destination, e -> new ArrayList<>());
40+
destTsMap.add(timestamp);
41+
return true;
42+
}
43+
44+
public int[] forwardPacket() {
45+
if (packetQueue.isEmpty()) {
46+
return new int[0];
47+
}
48+
Packet packet = packetQueue.remove();
49+
packetSet.remove(packet);
50+
int dest = packet.destination;
51+
List<Integer> tsMap = destinationMap.get(dest);
52+
tsMap.removeFirst(); // O(n)
53+
return new int[]{packet.source, packet.destination, packet.timestamp};
54+
}
55+
56+
public int getCount(int destination, int startTime, int endTime) {
57+
List<Integer> tsMap = destinationMap.get(destination);
58+
if (tsMap == null) {
59+
return 0;
60+
}
61+
int i = lowerBound(tsMap, startTime);
62+
int j = lowerBound(tsMap, endTime + 1);
63+
return j - i;
64+
}
65+
66+
private int lowerBound(List<Integer> a, int key) {
67+
int l = 0, r = a.size();
68+
while (l < r) {
69+
int m = l + (r - l) / 2;
70+
if (a.get(m) >= key) r = m;
71+
else l = m + 1;
72+
}
73+
return l;
74+
}
75+
}
76+
77+
// 每个 destination 一个动态开点线段树
78+
static class Router2 {
79+
record Packet(int source, int destination, int timestamp) {
80+
}
81+
82+
int memoryLimit;
83+
Queue<Packet> packetQueue;
84+
Set<Packet> packetSet;
85+
Map<Integer, DynamicLazySegmentTree> destinationMap;
86+
87+
public Router2(int memoryLimit) {
88+
this.memoryLimit = memoryLimit;
89+
this.packetQueue = new ArrayDeque<>();
90+
this.packetSet = new HashSet<>();
91+
this.destinationMap = new HashMap<>();
92+
}
93+
94+
public boolean addPacket(int source, int destination, int timestamp) {
95+
Packet newPacket = new Packet(source, destination, timestamp);
96+
if (packetSet.contains(newPacket)) {
97+
return false;
98+
}
99+
if (packetQueue.size() >= memoryLimit) {
100+
forwardPacket();
101+
}
102+
packetQueue.add(newPacket);
103+
packetSet.add(newPacket);
104+
105+
DynamicLazySegmentTree destTsMap = destinationMap.computeIfAbsent(destination, k -> new DynamicLazySegmentTree());
106+
destTsMap.rangeApply(timestamp, timestamp, 1);
107+
return true;
108+
}
109+
110+
public int[] forwardPacket() {
111+
if (packetQueue.isEmpty()) {
112+
return new int[0];
113+
}
114+
Packet packet = packetQueue.remove();
115+
packetSet.remove(packet);
116+
int dest = packet.destination;
117+
int ts = packet.timestamp;
118+
DynamicLazySegmentTree tsMap = destinationMap.get(dest);
119+
tsMap.rangeApply(ts, ts, -1);
120+
return new int[]{packet.source, packet.destination, packet.timestamp};
121+
}
122+
123+
public int getCount(int destination, int startTime, int endTime) {
124+
DynamicLazySegmentTree tsMap = destinationMap.get(destination);
125+
if (tsMap == null) {
126+
return 0;
127+
}
128+
return (int) tsMap.query(startTime, endTime);
129+
}
130+
131+
// 动态开点线段树模板,只需要实现 mergeInfo 和 _do,其余都是固定的
132+
static class DynamicLazySegmentTree {
133+
static final int N = (int) (1e9 + 10);
134+
final Node root = new Node();
135+
136+
static class Node {
137+
Node ls, rs;
138+
long sum, lazy;
139+
}
140+
141+
long mergeInfo(Node ls, Node rs) {
142+
return ls.sum + rs.sum;
143+
}
144+
145+
void _do(Node p, int l, int r, long qv) {
146+
p.sum += (r - l + 1L) * qv;
147+
p.lazy += qv;
148+
}
149+
150+
void rangeApply(int ql, int qr, int val) {
151+
this.rangeApply(root, 0, N, ql, qr, val);
152+
}
153+
154+
void rangeApply(Node p, int l, int r, int ql, int qr, int qv) {
155+
if (ql <= l && r <= qr) {
156+
_do(p, l, r, qv);
157+
return;
158+
}
159+
int m = l + (r - l) / 2;
160+
spread(p, l, r, m);
161+
if (ql <= m) rangeApply(p.ls, l, m, ql, qr, qv);
162+
if (qr > m) rangeApply(p.rs, m + 1, r, ql, qr, qv);
163+
maintain(p);
164+
}
165+
166+
long query(int ql, int qr) {
167+
return query(root, 0, N, ql, qr);
168+
}
169+
170+
long query(Node p, int l, int r, int ql, int qr) {
171+
if (ql <= l && r <= qr) {
172+
return p.sum;
173+
}
174+
int m = l + (r - l) / 2;
175+
spread(p, l, r, m);
176+
if (qr <= m) return query(p.ls, l, m, ql, qr);
177+
if (ql > m) return query(p.rs, m + 1, r, ql, qr);
178+
return query(p.ls, l, m, ql, qr) + query(p.rs, m + 1, r, ql, qr);
179+
}
180+
181+
void spread(Node p, int l, int r, int m) {
182+
if (p.ls == null) p.ls = new Node();
183+
if (p.rs == null) p.rs = new Node();
184+
if (p.lazy != 0) {
185+
_do(p.ls, l, m, p.lazy);
186+
_do(p.rs, m + 1, r, p.lazy);
187+
p.lazy = 0;
188+
}
189+
}
190+
191+
void maintain(Node p) {
192+
p.sum = mergeInfo(p.ls, p.rs);
193+
}
194+
}
195+
}
196+
}
197+
/*
198+
3508. 设计路由器
199+
https://leetcode.cn/problems/implement-router/description/
200+
201+
第 444 场周赛 T2。
202+
203+
请你设计一个数据结构来高效管理网络路由器中的数据包。每个数据包包含以下属性:
204+
- source:生成该数据包的机器的唯一标识符。
205+
- destination:目标机器的唯一标识符。
206+
- timestamp:该数据包到达路由器的时间戳。
207+
实现 Router 类:
208+
Router(int memoryLimit):初始化路由器对象,并设置固定的内存限制。
209+
- memoryLimit 是路由器在任意时间点可以存储的 最大 数据包数量。
210+
- 如果添加一个新数据包会超过这个限制,则必须移除 最旧的 数据包以腾出空间。
211+
bool addPacket(int source, int destination, int timestamp):将具有给定属性的数据包添加到路由器。
212+
- 如果路由器中已经存在一个具有相同 source、destination 和 timestamp 的数据包,则视为重复数据包。
213+
- 如果数据包成功添加(即不是重复数据包),返回 true;否则返回 false。
214+
int[] forwardPacket():以 FIFO(先进先出)顺序转发下一个数据包。
215+
- 从存储中移除该数据包。
216+
- 以数组 [source, destination, timestamp] 的形式返回该数据包。
217+
- 如果没有数据包可以转发,则返回空数组。
218+
int getCount(int destination, int startTime, int endTime):
219+
- 返回当前存储在路由器中(即尚未转发)的,且目标地址为指定 destination 且时间戳在范围 [startTime, endTime](包括两端)内的数据包数量。
220+
注意:对于 addPacket 的查询会按照 timestamp 的递增顺序进行。
221+
提示:
222+
2 <= memoryLimit <= 10^5
223+
1 <= source, destination <= 2 * 10^5
224+
1 <= timestamp <= 10^9
225+
1 <= startTime <= endTime <= 10^9
226+
addPacket、forwardPacket 和 getCount 方法的总调用次数最多为 10^5。
227+
对于 addPacket 的查询,timestamp 按递增顺序给出。
228+
229+
题目保证 timestamp 递增,可以在队列上二分。
230+
如果不保证递增,则需要动态开点线段树。
231+
*/
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import java.util.Arrays;
2+
import java.util.HashSet;
3+
import java.util.Set;
4+
5+
public class Solution3509 {
6+
private int[] nums;
7+
private int k, limit;
8+
private Set<String> memo;
9+
private int ans = -1;
10+
11+
public int maxProduct(int[] nums, int k, int limit) {
12+
this.nums = nums;
13+
this.k = k;
14+
this.limit = limit;
15+
int sum = Arrays.stream(nums).sum();
16+
if (sum < Math.abs(k)) return -1;
17+
18+
memo = new HashSet<>();
19+
dfs(0, 0, 1, false, true);
20+
return ans;
21+
}
22+
23+
// s:加法单位元是 0
24+
// m:乘法单位元是 1
25+
private void dfs(int i, int s, int m, boolean odd, boolean empty) {
26+
if (ans == limit) return; // 已经达到最大值
27+
if (i == nums.length) {
28+
if (!empty && s == k && m <= limit) {
29+
ans = Math.max(ans, m);
30+
}
31+
return;
32+
}
33+
34+
String key = i + ":" + s + ":" + m + ":" + odd + ":" + empty;
35+
if (!memo.add(key)) return;
36+
// 不选 x
37+
dfs(i + 1, s, m, odd, empty);
38+
// 选 x
39+
int x = nums[i];
40+
dfs(i + 1, s + (odd ? -x : x), Math.min(m * x, limit + 1), !odd, false);
41+
}
42+
}
43+
/*
44+
3509. 最大化交错和为 K 的子序列乘积
45+
https://leetcode.cn/problems/maximum-product-of-subsequences-with-an-alternating-sum-equal-to-k/description/
46+
47+
第 444 场周赛 T3。
48+
49+
给你一个整数数组 nums 和两个整数 k 与 limit,你的任务是找到一个非空的 子序列,满足以下条件:
50+
- 它的 交错和 等于 k。
51+
- 在乘积 不超过 limit 的前提下,最大化 其所有数字的乘积。
52+
返回满足条件的子序列的 乘积 。如果不存在这样的子序列,则返回 -1。
53+
子序列 是指可以通过删除原数组中的某些(或不删除)元素并保持剩余元素顺序得到的新数组。
54+
交错和 是指一个 从下标 0 开始 的数组中,偶数下标 的元素之和减去 奇数下标 的元素之和。
55+
提示:
56+
1 <= nums.length <= 150
57+
0 <= nums[i] <= 12
58+
-10^5 <= k <= 10^5
59+
1 <= limit <= 5000
60+
61+
暴力出奇迹:如何分析状态个数
62+
https://leetcode.cn/problems/maximum-product-of-subsequences-with-an-alternating-sum-equal-to-k/solutions/3641716/bao-li-sou-suo-by-endlesscheng-j3bl/
63+
150 个 [1,12] 中的数相乘,只有 M=394 个 ≤5000 的不同乘积。
64+
rating 2677 (clist.by)
65+
*/

0 commit comments

Comments
(0)

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