Skip to content

Commit 104d574

Browse files
committed
2565 & 第98场双周赛T1~T4 & 第333场周赛T1~T4 (9)
1 parent 36d870a commit 104d574

19 files changed

+751
-1
lines changed

atcoder-beginner/src/main/java/c287/Abc287_d.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,7 @@ private static String solve(String s, String t) {
4646
D - Match or Not
4747
https://atcoder.jp/contests/abc287/tasks/abc287_d
4848
49-
预处理 前后缀
49+
前后缀分解
50+
相似题目: 2565. 最少得分子序列
51+
https://leetcode.cn/problems/subsequence-with-the-minimum-score/
5052
*/
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
public class Solution2565 {
2+
public int minimumScore(String s, String t) {
3+
int n = s.length();
4+
int m = t.length();
5+
6+
// pre[i] = x 表示 t 前缀长度为 i 时,s 需要至少前缀长度 x 匹配
7+
int[] pre = new int[m + 1];
8+
pre[0] = 0;
9+
int j = 1;
10+
// s[j] t[i]
11+
for (int i = 1; i <= m; i++) {
12+
while (j <= n && s.charAt(j - 1) != t.charAt(i - 1)) {
13+
j++;
14+
}
15+
if (j <= n) {
16+
pre[i] = j++;
17+
} else {
18+
pre[i] = n + 1;
19+
}
20+
}
21+
22+
// suf[i] = x 表示 t 后缀长度为 i 时,s 需要至少后缀长度 x 匹配
23+
int[] suf = new int[m + 1];
24+
// suf[0] = 0;
25+
suf[m] = 0;
26+
j = 1;
27+
for (int i = 1; i <= m; i++) {
28+
while (j <= n && s.charAt(n - j) != t.charAt(m - i)) {
29+
j++;
30+
}
31+
if (j <= n) {
32+
// suf[i] = j++;
33+
suf[m - i] = j++;
34+
} else {
35+
// suf[i] = n + 1;
36+
suf[m - i] = n + 1;
37+
}
38+
}
39+
40+
// 二分删除长度
41+
int left = 0;
42+
int right = m;
43+
while (left < right) {
44+
int mid = left + (right - left) / 2;
45+
// 边界二分 F, F,..., F, [T, T,..., T]
46+
// ----------------------^
47+
if (checkMid(n, m, pre, suf, mid)) {
48+
right = mid;
49+
} else {
50+
left = mid + 1;
51+
}
52+
}
53+
return left;
54+
}
55+
56+
private boolean checkMid(int n, int m, int[] pre, int[] suf, int mid) {
57+
for (int i = 0; i + mid <= m; i++) {
58+
if (pre[i] + suf[i + mid] <= n) {
59+
return true;
60+
}
61+
}
62+
return false;
63+
}
64+
}
65+
/*
66+
2565. 最少得分子序列
67+
https://leetcode.cn/problems/subsequence-with-the-minimum-score/
68+
69+
第 332 场周赛 T4。
70+
71+
给你两个字符串 s 和 t 。
72+
你可以从字符串 t 中删除任意数目的字符。
73+
如果没有从字符串 t 中删除字符,那么得分为 0 ,否则:
74+
- 令 left 为删除字符中的最小下标。
75+
- 令 right 为删除字符中的最大下标。
76+
字符串的得分为 right - left + 1 。
77+
请你返回使 t 成为 s 子序列的最小得分。
78+
一个字符串的 子序列 是从原字符串中删除一些字符后(也可以一个也不删除),剩余字符不改变顺序得到的字符串。(比方说 "ace" 是 "abcde" 的子序列,但是 "aec" 不是)。
79+
提示:
80+
1 <= s.length, t.length <= 10^5
81+
s 和 t 都只包含小写英文字母。
82+
83+
前后缀分解 + 二分(感觉比双指针好理解)
84+
相似题目: 2484. 统计回文子序列数目
85+
https://leetcode.cn/problems/count-palindromic-subsequences/
86+
2552. 统计上升四元组
87+
https://leetcode.cn/problems/count-increasing-quadruplets/
88+
D - Match or Not
89+
https://atcoder.jp/contests/abc287/tasks/abc287_d
90+
*/
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
import java.util.ArrayList;
2+
import java.util.List;
3+
4+
public class Solution6358 {
5+
public long[] handleQuery(int[] nums1, int[] nums2, int[][] queries) {
6+
long sum2 = 0L;
7+
for (int x : nums2) {
8+
sum2 += x;
9+
}
10+
11+
SegmentTree segmentTree = new SegmentTree(nums1);
12+
List<Long> resList = new ArrayList<>();
13+
for (int[] query : queries) {
14+
if (query[0] == 1) {
15+
segmentTree.op1(query[1] + 1, query[2] + 1);
16+
} else if (query[0] == 2) {
17+
sum2 += segmentTree.getSum() * query[1];
18+
} else {
19+
resList.add(sum2);
20+
}
21+
}
22+
return resList.stream().mapToLong(Long::longValue).toArray();
23+
}
24+
25+
private static class SegmentTree {
26+
private final int N;
27+
private final int[] nums;
28+
29+
private final long[] sum;
30+
private final int[] lazy;
31+
32+
public SegmentTree(int[] nums) {
33+
N = nums.length;
34+
this.nums = nums;
35+
36+
sum = new long[N * 4];
37+
lazy = new int[N * 4];
38+
build(1, N, 1);
39+
}
40+
41+
// 建树
42+
private void build(int s, int t, int p) {
43+
if (s == t) {
44+
sum[p] = nums[s - 1];
45+
return;
46+
}
47+
int mid = s + (t - s) / 2;
48+
build(s, mid, p * 2);
49+
build(mid + 1, t, p * 2 + 1);
50+
pushUp(p);
51+
}
52+
53+
// 将 nums1 从下标 l 到下标 r 的所有 0 反转成 1 或将 1 反转成 0 。
54+
public void op1(int l, int r) {
55+
this.op1(l, r, 1, N, 1);
56+
}
57+
58+
// 区间 [l,r] 求和
59+
public long getSum() {
60+
return this.getSum(1, N, 1, N, 1);
61+
}
62+
63+
private void op1(int l, int r, int s, int t, int p) {
64+
if (l <= s && t <= r) {
65+
sum[p] = (t - s + 1L) - sum[p];
66+
lazy[p] ^= 1;
67+
return;
68+
}
69+
int mid = s + (t - s) / 2;
70+
pushDown(mid, s, t, p);
71+
if (l <= mid) {
72+
op1(l, r, s, mid, p * 2);
73+
}
74+
if (r > mid) {
75+
op1(l, r, mid + 1, t, p * 2 + 1);
76+
}
77+
pushUp(p);
78+
}
79+
80+
private long getSum(int l, int r, int s, int t, int p) {
81+
if (l <= s && t <= r) {
82+
return sum[p];
83+
}
84+
int mid = s + (t - s) / 2;
85+
pushDown(mid, s, t, p);
86+
long sum = 0;
87+
if (l <= mid) {
88+
sum = getSum(l, r, s, mid, p * 2);
89+
}
90+
if (r > mid) {
91+
sum += getSum(l, r, mid + 1, t, p * 2 + 1);
92+
}
93+
return sum;
94+
}
95+
96+
private void pushDown(int mid, int s, int t, int p) {
97+
if (lazy[p] > 0) {
98+
sum[p * 2] = (mid - s + 1L) - sum[p * 2];
99+
sum[p * 2 + 1] = (t - mid) - sum[p * 2 + 1];
100+
lazy[p * 2] ^= lazy[p];
101+
lazy[p * 2 + 1] ^= lazy[p];
102+
lazy[p] = 0;
103+
}
104+
}
105+
106+
private void pushUp(int p) {
107+
sum[p] = sum[p * 2] + sum[p * 2 + 1];
108+
}
109+
}
110+
}
111+
/*
112+
6358. 更新数组后处理求和查询
113+
https://leetcode.cn/problems/handling-sum-queries-after-update/
114+
115+
第 98 场双周赛 T4。
116+
117+
给你两个下标从 0 开始的数组 nums1 和 nums2 ,和一个二维数组 queries 表示一些操作。总共有 3 种类型的操作:
118+
1. 操作类型 1 为 queries[i] = [1, l, r] 。你需要将 nums1 从下标 l 到下标 r 的所有 0 反转成 1 或将 1 反转成 0 。l 和 r 下标都从 0 开始。
119+
2. 操作类型 2 为 queries[i] = [2, p, 0] 。对于 0 <= i < n 中的所有下标,令 nums2[i] = nums2[i] + nums1[i] * p 。
120+
3. 操作类型 3 为 queries[i] = [3, 0, 0] 。求 nums2 中所有元素的和。
121+
请你返回一个数组,包含所有第三种操作类型的答案。
122+
提示:
123+
1 <= nums1.length,nums2.length <= 10^5
124+
nums1.length = nums2.length
125+
1 <= queries.length <= 10^5
126+
queries[i].length = 3
127+
0 <= l <= r <= nums1.length - 1
128+
0 <= p <= 10^6
129+
0 <= nums1[i] <= 1
130+
0 <= nums2[i] <= 10^9
131+
132+
线段树。基于 nums1 建树,懒标记下推 pushDown
133+
时间复杂度 O(n + qlogn)
134+
空间复杂度 O(4n)
135+
*/
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
public class Solution6359 {
2+
public int minMaxDifference(int num) {
3+
int min = Integer.MAX_VALUE;
4+
int max = 0;
5+
String str = String.valueOf(num);
6+
for (char i = '0'; i <= '9'; i++) {
7+
for (char j = '0'; j <= '9'; j++) {
8+
if (i == j) continue;
9+
int n = Integer.parseInt(str.replace(i, j));
10+
min = Math.min(min, n);
11+
max = Math.max(max, n);
12+
}
13+
}
14+
return max - min;
15+
}
16+
}
17+
/*
18+
6359. 替换一个数字后的最大差值
19+
https://leetcode.cn/problems/maximum-difference-by-remapping-a-digit/
20+
21+
第 98 场双周赛 T1。
22+
23+
给你一个整数 num 。你知道 Danny Mittal 会偷偷将 0 到 9 中的一个数字 替换 成另一个数字。
24+
请你返回将 num 中 恰好一个 数字进行替换后,得到的最大值和最小值的差位多少。
25+
注意:
26+
- 当 Danny 将一个数字 d1 替换成另一个数字 d2 时,Danny 需要将 nums 中所有 d1 都替换成 d2 。
27+
- Danny 可以将一个数字替换成它自己,也就是说 num 可以不变。
28+
- Danny 可以将数字分别替换成两个不同的数字分别得到最大值和最小值。
29+
- 替换后得到的数字可以包含前导 0 。
30+
- Danny Mittal 获得周赛 326 前 10 名,让我们恭喜他。
31+
提示:
32+
1 <= num <= 10^8
33+
34+
暴力
35+
*/
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import java.util.HashSet;
2+
import java.util.Set;
3+
4+
public class Solution6360 {
5+
public int minImpossibleOR(int[] nums) {
6+
Set<Integer> set = new HashSet<>();
7+
for (int x : nums) {
8+
set.add(x);
9+
}
10+
11+
int x = 1;
12+
while (true) {
13+
if (!set.contains(x)) {
14+
return x;
15+
}
16+
x <<= 1;
17+
}
18+
}
19+
}
20+
/*
21+
6360. 最小无法得到的或值
22+
https://leetcode.cn/problems/minimum-impossible-or/
23+
24+
给你一个下标从 0 开始的整数数组 nums 。
25+
如果存在一些整数满足 0 <= index1 < index2 < ... < indexk < nums.length ,得到 nums[index1] | nums[index2] | ... | nums[indexk] = x ,那么我们说 x 是 可表达的 。换言之,如果一个整数能由 nums 的某个子序列的或运算得到,那么它就是可表达的。
26+
请你返回 nums 不可表达的 最小非零整数 。
27+
提示:
28+
1 <= nums.length <= 10^5
29+
1 <= nums[i] <= 10^9
30+
31+
脑筋急转弯。位运算。
32+
只需考虑 二次幂 的数即可,非二次幂都可以由比它小的 二次幂 组合得到。
33+
时间复杂度 O(n + logmax(nums[i]))
34+
空间复杂度 O(n)
35+
*/
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
import java.util.Arrays;
2+
3+
public class Solution6361 {
4+
public int minimizeSum(int[] nums) {
5+
int n = nums.length;
6+
Arrays.sort(nums);
7+
8+
int res1 = nums[n - 3] - nums[0];
9+
int res2 = nums[n - 2] - nums[1];
10+
int res3 = nums[n - 1] - nums[2];
11+
return Math.min(res1, Math.min(res2, res3));
12+
}
13+
}
14+
/*
15+
6361. 修改两个元素的最小分数
16+
https://leetcode.cn/problems/minimum-score-by-changing-two-elements/
17+
18+
第 98 场双周赛 T2。
19+
20+
给你一个下标从 0 开始的整数数组 nums 。
21+
- nums 的 最小 得分是满足 0 <= i < j < nums.length 的 |nums[i] - nums[j]| 的最小值。
22+
- nums的 最大 得分是满足 0 <= i < j < nums.length 的 |nums[i] - nums[j]| 的最大值。
23+
- nums 的分数是 最大 得分与 最小 得分的和。
24+
我们的目标是最小化 nums 的分数。你 最多 可以修改 nums 中 2 个元素的值。
25+
请你返回修改 nums 中 至多两个 元素的值后,可以得到的 最小分数 。
26+
|x| 表示 x 的绝对值。
27+
提示:
28+
3 <= nums.length <= 10^5
29+
1 <= nums[i] <= 10^9
30+
31+
脑筋急转弯,只需考虑三种情况。
32+
*/
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import java.util.Map;
2+
import java.util.TreeMap;
3+
4+
public class Solution6362 {
5+
public int[][] mergeArrays(int[][] nums1, int[][] nums2) {
6+
TreeMap<Integer, Integer> treeMap = new TreeMap<>();
7+
for (int[] x : nums1) {
8+
treeMap.put(x[0], x[1]);
9+
}
10+
for (int[] x : nums2) {
11+
treeMap.put(x[0], treeMap.getOrDefault(x[0], 0) + x[1]);
12+
}
13+
14+
int[][] res = new int[treeMap.size()][2];
15+
int i = 0;
16+
for (Map.Entry<Integer, Integer> entry : treeMap.entrySet()) {
17+
res[i++] = new int[]{entry.getKey(), entry.getValue()};
18+
}
19+
return res;
20+
}
21+
}
22+
/*
23+
6362. 合并两个二维数组 - 求和法
24+
https://leetcode.cn/problems/merge-two-2d-arrays-by-summing-values/
25+
26+
第 333 场周赛 T1。
27+
28+
给你两个 二维 整数数组 nums1 和 nums2.
29+
- nums1[i] = [idi, vali] 表示编号为 idi 的数字对应的值等于 vali 。
30+
- nums2[i] = [idi, vali] 表示编号为 idi 的数字对应的值等于 vali 。
31+
每个数组都包含 互不相同 的 id ,并按 id 以 递增 顺序排列。
32+
请你将两个数组合并为一个按 id 以递增顺序排列的数组,并符合下述条件:
33+
- 只有在两个数组中至少出现过一次的 id 才能包含在结果数组内。
34+
- 每个 id 在结果数组中 只能出现一次 ,并且其对应的值等于两个数组中该 id 所对应的值求和。如果某个数组中不存在该 id ,则认为其对应的值等于 0 。
35+
返回结果数组。返回的数组需要按 id 以递增顺序排列。
36+
提示:
37+
1 <= nums1.length, nums2.length <= 200
38+
nums1[i].length == nums2[j].length == 2
39+
1 <= idi, vali <= 1000
40+
数组中的 id 互不相同
41+
数据均按 id 以严格递增顺序排列
42+
43+
TreeMap 模拟
44+
*/

0 commit comments

Comments
 (0)