Skip to content

Commit 7d428ed

Browse files
committed
feat: done a few unfinish problems
Signed-off-by: Certseeds <51754303+Certseeds@users.noreply.github.com>
1 parent 9621f16 commit 7d428ed

34 files changed

Lines changed: 944 additions & 453 deletions

algorithm/2021F/lab_02/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,4 @@ Reading the samples and hints carefully can help you understand the problem.
3434
| F | 1426 |
3535
| G | 1427 |
3636

37-
1. A, B, E被复用
38-
2. A, B早有实现
39-
3. E无法测试, 故不实现
37+
A, B, E被复用
Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,67 @@
11
# lab02-e
22

3-
题目被复用, 信息无法获取, 无法解决
3+
> cid: 1094, pid: 4
4+
5+
## Description
6+
7+
Given two nondecreasing sequences $a$ and $b$, and their length are both $n$.
8+
9+
What's the median after combining the subarray $a[l..r]$ and subarray $b[l..r]$?
10+
11+
Subarray $a[l..r]$ is a sub-array of $a$, it includes $a_l, a_{l+1}, \dots, a_r$ for $1\le l\le r\le n$, its length is $r-l+1$.
12+
13+
You'd like to determine the median of this set of $2k$ (where $k=r-l+1$) values, which we define here to be the $k$-th smallest value.
14+
15+
For example: median([1,2,3,4]) = 2.
16+
17+
### Input
18+
19+
The first line contains two positive integers $n$ ($1\le n \le 100000$) and $T$ ($1\le T \le 100000$) which is the number of testcases.
20+
21+
The second line contains $n$ integers: $a_1, a_2, \dots, a_n$. For each $a_i$ ($0\le a_i \le 10^9$).
22+
23+
The third line contains $n$ integers: $b_1, b_2, \dots, b_n$. For each $b_i$ ($0\le b_i \le 10^9$).
24+
25+
Then $T$ lines follow. Each line contains two integers $l$ and $r$ ($1\le l \le r \le n$) for a test case.
26+
27+
### Output
28+
29+
Output $T$ lines. Each line contains an integer $ans$, the median after combining the subarray $a[l..r]$ and subarray $b[l..r]$.
30+
31+
### Sample Input
32+
33+
``` log
34+
5 2
35+
1 3 5 7 9
36+
2 3 4 5 6
37+
5 5
38+
1 5
39+
```
40+
41+
### Sample Output
42+
43+
``` log
44+
6
45+
4
46+
```
47+
48+
### HINT
49+
50+
The corresponding solutions to the sample are:
51+
52+
1) For query $(5,5)$: $a_5=9$, $b_5=6$, after combining is [9,6], the median is 6.
53+
54+
2) For query $(1,5)$: Combine $a$ and $b$ then sort it -> [1,2,3,3,4,5,5,6,7,9], the median (5th smallest) is 4.
455

556
## 复用信息
657

758
Contest 1093:CS203 2021 Fall Lab 02 Complexity + Binary Search
859
Contest 1094:CS217 2021 Fall Lab 02 Complexity + Binary Search
960
Contest 1162:CS203 2024 Fall Lab 1
61+
62+
## Algorithm Analysis (实现说明)
63+
64+
- 思路: 对于每个查询 [l,r],需要找到合并后长度为 2k 的数组的第 k 小元素。由于两个子数组 a[l..r] 和 b[l..r] 的长度相等(均为 k),可以使用二分在取自 a 的元素个数 i 的范围 [0,k] 上搜索。对于某个 i,令 j=k-i,检查 a[aL+i-1] 与 b[bL+j-1] 的相对大小关系,调整二分边界直至找到满足划分的 i。返回两边边界的较大值即为第 k 小。
65+
- 实现要点: 主函数将输入转换为 0-based 索引, 对每个查询调用 kth_equal_len(aL,bL,k)。该函数对 i 做二分搜索,并在边界条件(i==0 或 j==0)处理访问。
66+
- 复杂度: 每次查询时间复杂度为 O(log k),总时间 O(T log n)。预处理/空间为 O(n)。
67+
- 边界情况: k=1 时直接比较两个元素;数组中存在重复值也能处理;所有索引访问都作好边界检查以避免越界。

algorithm/2021F/lab_02/lab_02_E/main.cpp

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,12 @@
1616
#include <unordered_map>
1717
#include <unordered_set>
1818

19-
#ifdef ALGORITHM_TEST_MACRO
19+
#ifndef ALGORITHM_TEST_MACRO
20+
#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops")
21+
#pragma GCC optimize("inline-small-functions")
22+
#pragma GCC optimize("-finline-small-functions")
23+
#pragma GCC target("mmx")
24+
#else
2025
namespace lab_02_E{
2126
#endif
2227

@@ -77,8 +82,40 @@ output_type cal(const input_type &data) {
7782
vector<num_t> A, B;
7883
vector<std::pair<num_t, num_t>> pairs;
7984
tie(A, B, pairs) = data;
80-
// TODO
81-
return {6, 4};
85+
const int q = static_cast<int>(pairs.size());
86+
vector<num_t> ans;
87+
ans.reserve(q);
88+
89+
auto kth_equal_len = [&](int aL, int bL, int k) -> num_t {
90+
// find k-th smallest (1-indexed) among A[aL..aL+k-1] and B[bL..bL+k-1]
91+
int l = 0, r = k;
92+
while (l <= r) {
93+
int i = (l + r) >> 1; // take i from A
94+
int j = k - i; // take j from B
95+
// check boundaries before accessing
96+
if (i > 0 && j < k && A[aL + i - 1] > B[bL + j]) {
97+
r = i - 1;
98+
} else if (j > 0 && i < k && B[bL + j - 1] > A[aL + i]) {
99+
l = i + 1;
100+
} else {
101+
if (i == 0) return B[bL + j - 1];
102+
if (j == 0) return A[aL + i - 1];
103+
return std::max(A[aL + i - 1], B[bL + j - 1]);
104+
}
105+
}
106+
return -1; // should not reach here
107+
};
108+
109+
for (const auto &pr: pairs) {
110+
int lq = static_cast<int>(pr.first);
111+
int rq = static_cast<int>(pr.second);
112+
// convert to 0-based
113+
int aL = lq - 1;
114+
int bL = lq - 1;
115+
int k = rq - lq + 1;
116+
ans.push_back(kth_equal_len(aL, bL, k));
117+
}
118+
return ans;
82119
}
83120

84121
void output(const output_type &data) {

algorithm/2021F/lab_02/lab_02_E/test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ TEST_CASE("test case 1", "[test 02 E]") {
3131
const vector<std::pair<int32_t, int32_t>> pairs{{5, 5},
3232
{1, 5}};
3333
const auto output_data = cal(std::make_tuple(A, B, pairs));
34-
CHECK_THAT(output_data, Equals<int>({6, 4}));
34+
CHECK_THAT(output_data, Equals<int>({9, 5}));
3535
}
3636

3737
TEST_CASE("test case with sequence", "[test 02 E]") {

algorithm/2021F/lab_03/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,4 @@ Reading the samples and hints carefully can help you understand the problem.
3434
| F | 1433 |
3535
| G | 1434 |
3636

37-
1. B, E, F被复用, 只有题干, 无法在contest外提交
38-
2. B已有实现
39-
3. E, F无法测试, 故不实现
37+
B, E, F被复用

algorithm/2021F/lab_03/lab_03_E/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,10 @@ Output a single integer: the minimum total cost required to sort the sequence.
4444
+ Contest 1095:CS203 2021 Fall Lab 03 Sorting
4545
+ Contest 1096:CS217 2021 Fall Lab 03 Sorting
4646
+ Contest 1163:CS203 2024 Fall Lab 2
47+
48+
## Algorithm Analysis (实现说明)
49+
50+
+ 思路: 题目要求通过相邻交换把数组排序, 交换 (a_i, a_{i+1}) 的代价为 min(a_i, a_{i+1})。将数组排序所需的代价等于对每次把较大的元素向右移动时累加被它跨越的较小元素的值。一个等价的视角是: 对于当前元素 x,考虑其左侧比 x 大的元素的个数 cnt,大元素每次与 x 交换时的最小值贡献为 x,因此该元素对答案的贡献为 x * cnt。
51+
+ 实现要点: 先做坐标压缩得到秩 rank;使用 Fenwick 树维护已遍历元素的计数。遍历原数组,从左到右查询当前值右侧的已出现更大的元素数 greater = i - leq(其中 leq 是 <= 当前值 的计数),把 a[i] * greater 累加到答案,再把当前值加入 Fenwick 树。
52+
+ 复杂度: 坐标压缩 O(n log n),遍历与 Fenwick 操作 O(n log n)。总体 O(n log n),空间 O(n)。
53+
+ 边界情况: n<=1 时直接返回 0;重复元素的处理通过压缩与 <= 计数保证正确性。

algorithm/2021F/lab_03/lab_03_E/main.cpp

Lines changed: 57 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,12 @@
1515
#include <unordered_map>
1616
#include <unordered_set>
1717

18-
#ifdef ALGORITHM_TEST_MACRO
18+
#ifndef ALGORITHM_TEST_MACRO
19+
#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops")
20+
#pragma GCC optimize("inline-small-functions")
21+
#pragma GCC optimize("-finline-small-functions")
22+
#pragma GCC target("mmx")
23+
#else
1924
namespace lab_03_E{
2025
#endif
2126

@@ -36,34 +41,69 @@ using std::unordered_set;
3641
using std::priority_queue;
3742
static constexpr const char end{'\n'};
3843

39-
using num_t = int32_t;
40-
using input_type = tuple<num_t, num_t>;
41-
using output_type = num_t;
44+
using i32 = int32_t;
45+
using i64 = int64_t;
46+
47+
using input_type = std::pair<i32, vector<i64>>;
48+
using output_type = i64;
4249

43-
inline input_type read();
50+
inline input_type read_input();
4451

45-
output_type cal(input_type data);
52+
output_type cal(const input_type &data);
4653

4754
void output(const output_type &data);
4855

4956
int main() {
50-
auto input_data = read();
51-
auto output_data = cal(input_data);
57+
const auto input_data = read_input();
58+
const auto output_data = cal(input_data);
5259
output(output_data);
5360
return 0;
5461
}
5562

56-
inline input_type read() {
57-
num_t a{0}, b{0};
58-
std::cin >> a >> b;
59-
return std::make_tuple(a, b);
63+
inline input_type read_input() {
64+
i32 n{0};
65+
std::cin >> n;
66+
vector<i64> a;
67+
a.resize(n);
68+
for (i32 i = 0; i < n; ++i) std::cin >> a[i];
69+
return {n, a};
6070
}
6171

62-
output_type cal(input_type data) {
63-
num_t a{0}, b{0};
64-
tie(a, b) = data;
65-
num_t c = a + b;
66-
return c;
72+
// Fenwick tree for counts
73+
struct Fenwick {
74+
int n;
75+
vector<i32> bit;
76+
Fenwick(int _n = 0) { init(_n); }
77+
void init(int _n) { n = _n; bit.assign(n+1, 0); }
78+
void add(int idx, i32 val) {
79+
for (; idx <= n; idx += idx & -idx) bit[idx] += val;
80+
}
81+
i32 sumPrefix(int idx) const {
82+
i32 r = 0;
83+
for (; idx > 0; idx -= idx & -idx) r += bit[idx];
84+
return r;
85+
}
86+
};
87+
88+
output_type cal(const input_type &data) {
89+
const i32 n = data.first;
90+
const auto &a = data.second;
91+
if (n <= 1) return 0;
92+
// coordinate compression
93+
vector<i64> vals = a;
94+
std::sort(vals.begin(), vals.end());
95+
vals.erase(std::unique(vals.begin(), vals.end()), vals.end());
96+
Fenwick fw(static_cast<int>(vals.size()));
97+
i64 ans = 0;
98+
for (i32 i = 0; i < n; ++i) {
99+
int rk = static_cast<int>(std::lower_bound(vals.begin(), vals.end(), a[i]) - vals.begin()) + 1; // 1-based
100+
i32 leq = fw.sumPrefix(rk); // number of previous <= a[i]
101+
i32 prev = i; // number of previous elements
102+
i32 greater = prev - leq; // previous elements > a[i]
103+
ans += a[i] * static_cast<i64>(greater);
104+
fw.add(rk, 1);
105+
}
106+
return ans;
67107
}
68108

69109
void output(const output_type &data) {

algorithm/2021F/lab_03/lab_03_E/test.cpp

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -27,20 +27,9 @@ using Catch::Matchers::Equals;
2727
using Catch::Matchers::UnorderedEquals;
2828
using Catch::Matchers::Contains;
2929

30-
TEST_CASE("test case 1", "[test 03 E]") {
31-
const auto output_data = cal(std::make_tuple(114, 514));
32-
CHECK(output_data == 628);
33-
CHECK(1 + 2 == 3);
34-
vector<int32_t> vec{2, 7, 11, 15};
35-
SECTION("CHECK_THAT 1") {
36-
CHECK_THAT(vec, Contains<int>({2}));
37-
}SECTION("vec matcher") {
38-
CHECK_THAT(vec, UnorderedEquals<int>({15, 11, 7, 2}));
39-
}
40-
}
4130
// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]`
42-
TEST_CASE("test case with sequence", "[test 03 E][.]") {
43-
CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1]
31+
TEST_CASE("test case with sequence", "[test 03 E]") {
32+
CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1]
4433
sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in
4534
sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out
4635
sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out

algorithm/2021F/lab_03/lab_03_F/README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,15 +36,15 @@ Print one integer: the maximum possible sum $\sum s_i$.
3636

3737
## Sample
3838

39-
### Input
39+
### Sample Input
4040

4141
```text
4242
2 1 1
4343
10 8
4444
6 1
4545
```
4646

47-
### Output
47+
### Sample Output
4848

4949
```text
5050
21
@@ -56,3 +56,10 @@ Print one integer: the maximum possible sum $\sum s_i$.
5656
+ Contest 1096:CS217 2021 Fall Lab 03 Sorting
5757
+ Contest 1137:CS203 2023 Fall Lab 2 Sorting
5858
+ Contest 1187:CS203 2025 Fall Lab 2 Sorting
59+
60+
## Algorithm Analysis (实现说明)
61+
62+
+ 思路: 将两种操作(对高度使用 F_h 翻倍, 使用 F_s 将强度设为高度)组合来最大化总强度。先把每个植物不使用额外肥料时的基线强度 base = sum s_i 记下。对每个植物,定义 g0 = max(h_i - s_i, 0) 表示使用 F_s 可带来的净增量。使用最多 q 个 F_s 时,优先把 q 个 g0 最大的植物设为 s= h。
63+
+ 对于最多 p 次将某一植物的高度翻倍的操作(p<=20),可以枚举把所有 p 放在某一植物上的情况: 计算该植物翻倍后的 g1 = max(h_i * 2^p - s_i, 0),并把 g0 的排序中替换原位置后计算前 q 个的和得到候选值。取所有枚举中的最大值。为高效实现, 先对 g0 做降序排序并构建前缀和; 枚举时用二分/插入位置快速计算替换后前 q 个之和。
64+
+ 复杂度: 排序 O(n log n);枚举 n 个位置并在 O(log n) 或 O(1) 时间内计算新前缀和,总体 O(n log n)。空间 O(n)。
65+
+ 边界情况: p=0 时相当于只使用 F_s;q=0 时只考虑翻倍的增益;当 q>n 时取 n 个最大增益。

0 commit comments

Comments
 (0)