diff --git a/.editorconfig b/.editorconfig index 81fa4d12..44597e6a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,10 +2,8 @@ root = true [*] charset = utf-8 +indent_size = 4 +end_of_line = lf indent_style = space insert_final_newline = true - -[*.{cpp,hpp}] -end_of_line = lf -indent_size = 4 trim_trailing_whitespace = true diff --git a/.gitattributes b/.gitattributes index 607cda74..29b9e521 100644 --- a/.gitattributes +++ b/.gitattributes @@ -14,6 +14,8 @@ *.template text diff=text *.in text eol=lf *.out text eol=lf +*.data.in text eol=lf +*.data.out text eol=lf # scripts *.sh text eol=lf diff --git a/LICENSE_APACHE_2_0.md b/LICENSE_APACHE_2_0.md new file mode 100644 index 00000000..261eeb9e --- /dev/null +++ b/LICENSE_APACHE_2_0.md @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 3358d648..9f511da1 100644 --- a/README.md +++ b/README.md @@ -116,7 +116,7 @@ git clone https://github.com/${YOUE_GITHUB_USER_NAME}/algorithm-template.git + 可选项: + 使用脚本产生自定义的文件(适合source.zip或者有bonuslab): - 使用命令行, 进入`./script`下, 编辑`file_template`的`labs` & `problem_orders`, + 使用命令行, 进入`./script`下, 编辑`file_template`的`labs` & `problem_orders`, `python3 ./file_template.py`, 出现`produce files finish`提示, 即为创建成功.

(back to top)

@@ -129,9 +129,9 @@ git clone https://github.com/${YOUE_GITHUB_USER_NAME}/algorithm-template.git `lab${order}_${ques_Order}`为对应题号, 比如`lab07_01`对应lab_07的C1题. -+ `CS203_lab07_01`将调用`lab_07\lab_07_C1\lab07_C1.cpp`, 为将要提交的源文件. -+ `CS203_lab07_01_test`将调用`lab_07\lab_07_C1\lab07_C1_test.cpp`, 对其进行测试. -+ `lab_*\lab_*_*\lab_*_*_test.cpp`目的为方便测试, 同时便于分享测试用例. ++ `CS203_lab07_01`将调用`lab_07\lab_07_C1\main.cpp`, 为将要提交的源文件. ++ `CS203_lab07_01_test`将调用`lab_07\lab_07_C1\test.cpp`, 对其进行测试. ++ `lab_*\lab_*_*\test.cpp`目的为方便测试, 同时便于分享测试用例.

(back to top)

@@ -153,7 +153,7 @@ git clone https://github.com/${YOUE_GITHUB_USER_NAME}/algorithm-template.git + 在本repo, 使用`Catch2`测试框架. + 比如, 我们有四组数据, 第一组, 第二组测试边界值, 第三组使用随机数测试对偶性与正确性, 第四组测试几个手动的随机值. - + 参见[test_for_lab00_A](./lab_00/lab_00_A/lab_00_A_test.cpp). + + 参见[test_for_lab00_A](./lab_00/lab_00_A/test.cpp). + 这样一来, 我们只需要每次修改完主文件之后, run `algorithm-template_test`, 对其进行调用, 就能验证其在所有的测试用例上的正确性. ### 多个输出值的检查:`Catch::Matchers` @@ -162,7 +162,7 @@ git clone https://github.com/${YOUE_GITHUB_USER_NAME}/algorithm-template.git 举例:[Crzay Plan](https://acm.sustech.edu.cn/onlinejudge/problem.php?id=1250), 输入可能有1.1*10^6个. -这种情况下对这么多值进行直接的观察就很难, 所以我们预先将期望的值直接写在测试文件里, 用Catch2内置的Matcher比较(见[test_for_lab00_B](./lab_00/lab_00_B/lab_00_B_test.cpp)的`CHECK_THAT()`部分.) +这种情况下对这么多值进行直接的观察就很难, 所以我们预先将期望的值直接写在测试文件里, 用Catch2内置的Matcher比较(见[test_for_lab00_B](./lab_00/lab_00_B/test.cpp)的`CHECK_THAT()`部分.) PS: 当然, 这种情况也只适用于规模比较小的情况, 规模再大的话, 直接由人手动写在测试文件里也太占空间了. @@ -192,7 +192,7 @@ TEST_CASE("test case 1", "[test 00 C]") { + test case with tuple 则最优雅, 修改起来的难度最小. + test case with sequence 比tuple更优雅, 输入, 输出全为自动产生. -PS: 此处注意, 引用文件的相对路径, 不是直接的`test/lab_00/lab_00_C/resource/01.data.in`, +PS: 此处注意, 引用文件的相对路径, 不是直接的`test/lab_00/lab_00_C/resource/01.data.in`, 而是编译出的文件相对于测试数据的相对路径. @@ -219,7 +219,7 @@ PS: 此处注意, 引用文件的相对路径, 不是直接的`test/lab_00/lab_0 PS: 至于比较文件之间的差异, 可以使用内置的`compareFiles(string path1, string path2)`函数进行比较. -参考[文本比对_test_case_2](./lab_00/lab_00_D/lab_00_D_test.cpp) +参考[文本比对_test_case_2](./lab_00/lab_00_D/test.cpp) ## Details @@ -252,11 +252,11 @@ DSAA既然内含Data structure, 就势必涉及到类似Node, Tree, Graph等等 ### 如何手动开优化 1. 将[magic_optimize](./include/magic_macro/magic_macro.hpp)内的内容粘贴到代码最上方. -2. 关闭同步, +2. 关闭同步, ``` cpp static const auto faster_streams = [] { - srand(time(nullptr)); + srand(time(nullptr)); // use time to init the random seed std::ios::sync_with_stdio(false); std::istream::sync_with_stdio(false); @@ -329,9 +329,13 @@ Don't forget to give the project a star! Thanks again! ## License +### MIT LICENSE + +根目录下, 使用脚本生成的代码均采用`Apache 2.0`协议, 严谨而宽松. + ### AGPLv3.0+ LICENSE -绝大多数代码(`*.cpp`, `*.hpp`, etc)基于 AGPLv3.0+协议: 限制最强的主流开源协议 +非模板部分代码(`*.cpp`, `*.hpp`, etc)基于 AGPLv3.0+协议: 限制最强的主流开源协议 + 由于本仓库设计只包括"上交"源码这一种场景, 因此实际上不存在二进制分发以及被云服务使用这种场景. + 具体内容请看[`LICENSE_AGPL_V3_0.md`](./LICENSE_AGPL_V3_0.md) diff --git a/algorithm/2021F/lab_02/CMakeLists.txt b/algorithm/2021F/lab_02/CMakeLists.txt index e558ffef..56aa09f6 100644 --- a/algorithm/2021F/lab_02/CMakeLists.txt +++ b/algorithm/2021F/lab_02/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -set(dependencies A B C D E F) +set(dependencies A B C D E F G) foreach (elementName IN LISTS dependencies) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${elementName}) endforeach () diff --git a/algorithm/2021F/lab_02/README.md b/algorithm/2021F/lab_02/README.md index d82c747e..f5615ec9 100644 --- a/algorithm/2021F/lab_02/README.md +++ b/algorithm/2021F/lab_02/README.md @@ -2,7 +2,36 @@ SPDX-License-Identifier: CC-BY-NC-SA-4.0 --- -# algorithm_2021F_lab02 +# Contest1093 - CS203 2021 Fall Lab 02 Complexity + Binary Search -1. 为了方便为单独的题目撰写README, 将每个题目的resource,source,test文件放在单独的一个文件夹内. +> cid: 1094 +Welcome to CS203 2021 Fall Lab 02! Enjoy this Lab! + +There are six problems for you to solve. + +Score: + ++ A: 10 ++ B: 15/10 ++ C: 15/10 ++ D: 20/15 ++ E: 20/15 ++ F: 20/20 ++ G: undefined/20 + +Reading the samples and hints carefully can help you understand the problem. + +## Problems + +| Problem |problem id| +|---:|---:| +| A | 1421 | +| B | 1422 | +| C | 1423 | +| D | 1424 | +| E | 1425 | +| F | 1426 | +| G | 1427 | + +A, B, E被复用 diff --git a/algorithm/2021F/lab_02/cs203.submit.csv b/algorithm/2021F/lab_02/cs203.submit.csv new file mode 100644 index 00000000..ac690828 --- /dev/null +++ b/algorithm/2021F/lab_02/cs203.submit.csv @@ -0,0 +1,8 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 280, 1, 232, 94, 6, 7, 86, 60, 766, 11, 114, 641 +B, 259, 3, 332, 146, 4, 9, 33, 786, 4, 130, 652 +C, 257, 290, 62, 12, 34, 655, 3, 160, 492 +D, 272, 621, 368, 12, 11, 88, 51, 1423, 16, 364, 1043 +E, 224, 809, 761, 9, 19, 183, 80, 2085, 6, 329, 1750 +F, 205, 762, 335, 55, 12, 274, 60, 1703, 18, 276, 1409 +Total, 1497, 4, 3046, 1766, 82, 53, 652, 318, 7418, 58, 1373, 5987 \ No newline at end of file diff --git a/algorithm/2021F/lab_02/cs217.submit.csv b/algorithm/2021F/lab_02/cs217.submit.csv new file mode 100644 index 00000000..17e4a49a --- /dev/null +++ b/algorithm/2021F/lab_02/cs217.submit.csv @@ -0,0 +1,9 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 28, 16, 12, 1, 6, 2, 65, 21, 44 +B, 27, 9, 6, 1, 43, 16, 27 +C, 25, 9, 2, 36, 15, 21 +D, 32, 30, 21, 1, 4, 2, 90, 40, 50 +E, 27, 17, 37, 1, 3, 6, 91, 31, 60 +F, 32, 93, 37, 9, 2, 17, 14, 204, 2, 89, 113 +G, 27, 62, 40, 1, 6, 5, 141, 38, 103 +Total, 198, 236, 153, 11, 4, 37, 31, 670, 2, 250, 418 \ No newline at end of file diff --git a/algorithm/2021F/lab_02/lab_02_A/CMakeLists.txt b/algorithm/2021F/lab_02/lab_02_A/CMakeLists.txt index 354751e1..40897f09 100644 --- a/algorithm/2021F/lab_02/lab_02_A/CMakeLists.txt +++ b/algorithm/2021F/lab_02/lab_02_A/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_02/lab_02_A/README.md b/algorithm/2021F/lab_02/lab_02_A/README.md new file mode 100644 index 00000000..29acfc4c --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_A/README.md @@ -0,0 +1,64 @@ + # Problem A (inferred) + +## Description + +Given a set of integers and several query values, determine for each query whether the value exists in the set. + +Output "YES" if it exists, otherwise output "NO". + +## Input + +- Line 1: integer n, the number of elements in the set. +- Line 2: n integers (space-separated), the elements of the set. +- Next: integer T, the number of queries. +- Next T integers (whitespace separated or one per line): the queries. + +## Output + +Output T lines. For each query print either: + +- `YES` if the queried value is in the set +- `NO` otherwise + +## Sample + +### Sample Input + +```text +4 +1 2 3 999999 +2 +99 +3 +``` + +### Sample Output + +```text +NO +YES +``` + +## Implementation notes + +- The provided implementation stores elements in an `unordered_set` and answers each query by O(1) average-time hash lookup. + +- Current code uses 32-bit signed integers; if input values may exceed int32 range, switch to 64-bit types. + +## 复用信息 + ++ Contest 1162:CS203 2024 Fall Lab 1 ++ Contest 1093:CS203 2021 Fall Lab 02 Complexity + Binary Search ++ Contest 1094:CS217 2021 Fall Lab 02 Complexity + Binary Search ++ Contest 1135:CS203 2023 Fall Lab 1 Complexity + Binary Search ++ Contest 1186:CS203 2025 Fall Lab 1 Complexity + Binary Search + +# Solution / 思路解析 + +- 思路概述:把给定集合中的元素放入一个哈希集合(`unordered_set`),对每个查询直接判断是否存在,从而以接近 O(1) 的均摊时间回答。 +- 算法要点:读取 n 个元素并插入 `unordered_set`;然后对每个查询,在哈希集合中查找并输出 `YES`/`NO`。 +- 复杂度:构建集合 O(n)(均摊),每次查询 O(1)(均摊),总时间 O(n + T)。空间 O(n)。 +- 边界与实现注意事项: + - 输入可能包含重复元素(哈希集合会自动去重),但查询逻辑不受影响。 + - 若数据可能超出 32 位范围,则把 `int32_t` 换成 `int64_t`。 + - 对于极端输入(非常大的 n),确保 reserve 集合以减少 rehash 开销(可选优化)。 diff --git a/algorithm/2021F/lab_02/lab_02_A/lab_02_A.cpp b/algorithm/2021F/lab_02/lab_02_A/main.cpp similarity index 100% rename from algorithm/2021F/lab_02/lab_02_A/lab_02_A.cpp rename to algorithm/2021F/lab_02/lab_02_A/main.cpp diff --git a/algorithm/2021F/lab_02/lab_02_A/lab_02_A_test.cpp b/algorithm/2021F/lab_02/lab_02_A/test.cpp similarity index 98% rename from algorithm/2021F/lab_02/lab_02_A/lab_02_A_test.cpp rename to algorithm/2021F/lab_02/lab_02_A/test.cpp index d64aaa4d..1b9f8c4a 100644 --- a/algorithm/2021F/lab_02/lab_02_A/lab_02_A_test.cpp +++ b/algorithm/2021F/lab_02/lab_02_A/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_02_A.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_02/lab_02_A/resource/"; } diff --git a/algorithm/2021F/lab_02/lab_02_B/CMakeLists.txt b/algorithm/2021F/lab_02/lab_02_B/CMakeLists.txt index c490830a..dac0839a 100644 --- a/algorithm/2021F/lab_02/lab_02_B/CMakeLists.txt +++ b/algorithm/2021F/lab_02/lab_02_B/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_02/lab_02_B/README.md b/algorithm/2021F/lab_02/lab_02_B/README.md new file mode 100644 index 00000000..4e27ccc9 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_B/README.md @@ -0,0 +1,55 @@ +# Problem B (inferred) + +## Description + +For each input integer x, compute and print the value (x * (x + 1) * (x + 2)) / 6. + +This equals the binomial coefficient C(x+2, 3). + +## Input + +- Line 1: integer T, the number of test cases. +- Next T lines (or whitespace separated values): each a single integer x. + +## Output + +Output T lines. The i-th line contains the integer result of `(x * (x + 1) * (x + 2)) / 6` for the i-th input x. + +## Sample + +### Sample Input + +```text +2 +1 +2 +``` + +### Sample Output + +```text +1 +4 +``` + +## Implementation notes + +- The implementation uses 64-bit integer arithmetic (`int64_t`) to reduce overflow risk. For very large x values consider using safe multiplication order or big integers. + +- Mathematically, the expression equals C(x+2, 3), which may help reasoning about constraints and correctness. + +## 复用信息 + ++ Contest 1186:CS203 2025 Fall Lab 1 Complexity + Binary Search ++ Contest 1093:CS203 2021 Fall Lab 02 Complexity + Binary Search ++ Contest 1094:CS217 2021 Fall Lab 02 Complexity + Binary Search ++ Contest 1135:CS203 2023 Fall Lab 1 Complexity + Binary Search + +## Solution / 思路解析 + +- 思路概述:数学上该式子等价于组合数 $C(x+2,3)$。程序直接按代数表达式 $(x\times(x+1)\times(x+2))/6$ 计算。 +- 实现要点:使用 `int64_t` 来保存中间乘积以避免溢出;若可能溢出 64 位,应使用大整数或按分步除法来减少中间值(例如先除以 2 或 3,当能整除时)。 +- 复杂度:每个测试用例的计算为 O(1),总时间 O(T)。空间 O(1)。 +- 边界与注意事项: + - 输入 x 若为负数(题面通常为非负),公式仍在整数意义下成立,但需确认题目约束。 + - 对于非常大的 x(接近 1e6~1e9),中间乘积可能超过 64 位,需按题面约束决定是否要更高精度类型或安全乘法顺序。 diff --git a/algorithm/2021F/lab_02/lab_02_B/lab_02_B.cpp b/algorithm/2021F/lab_02/lab_02_B/main.cpp similarity index 100% rename from algorithm/2021F/lab_02/lab_02_B/lab_02_B.cpp rename to algorithm/2021F/lab_02/lab_02_B/main.cpp diff --git a/algorithm/2021F/lab_02/lab_02_B/lab_02_B_test.cpp b/algorithm/2021F/lab_02/lab_02_B/test.cpp similarity index 98% rename from algorithm/2021F/lab_02/lab_02_B/lab_02_B_test.cpp rename to algorithm/2021F/lab_02/lab_02_B/test.cpp index 3ec7c3b6..8d3ce997 100644 --- a/algorithm/2021F/lab_02/lab_02_B/lab_02_B_test.cpp +++ b/algorithm/2021F/lab_02/lab_02_B/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_02_B.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_02/lab_02_B/resource/"; } diff --git a/algorithm/2021F/lab_02/lab_02_C/CMakeLists.txt b/algorithm/2021F/lab_02/lab_02_C/CMakeLists.txt index 5de3f24f..f07d2e4c 100644 --- a/algorithm/2021F/lab_02/lab_02_C/CMakeLists.txt +++ b/algorithm/2021F/lab_02/lab_02_C/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_02/lab_02_C/README.md b/algorithm/2021F/lab_02/lab_02_C/README.md new file mode 100644 index 00000000..b489481b --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_C/README.md @@ -0,0 +1,46 @@ +# Problem C (Order 1423) + +## Description + +Given $F(x) = x e^{x/20} - b$, $x \in \mathbb{R}$. Here $e$ is Euler's number (approximately $2.718281828459\ldots$), and $b$ is a given integer. + +Please find a root of $F(x)$. + +## Input + +The 1st line is a positive integer $T$ ($1 \le T \le 1000$) which is the number of test cases. + +Then $T$ lines follow. Each line has an integer $b$ ($1 \le b \le 10^8$) for a test case. + +## Output + +Output $T$ lines. + +Each line contains a number $ans$ (accurate up to 10 decimal places), representing the approximate zero point of $F(x)$ and $|F(ans)| < 0.01$. + +## Sample Input + +```text +2 +1 +20 +``` + +## Sample Output + +```text +0.9448242188 +11.3433837891 +``` + +## Hint + +This problem uses special judge, so the sample output is not the only answer. + +## Solution / 思路解析 + +- 思路概述:要解方程 $F(x)=x e^{x/20}-b=0$,可以对 $x$ 使用二分查找或数值方法(如二分/牛顿法)。题目实现采用对 $x$ 在合理区间做二分搜索,直到函数值接近 0(满足精度要求)。 +- 关键细节:给定 $b$ 不同,其对应根 $x$ 在不同范围。实现中选取了固定的左右边界(例如 $[0.9, 258]$ 覆盖题目约束),然后在该区间内通过计算 $f(x)=x e^{x/20}-b$ 并根据符号向左或向右收缩区间,即典型的二分求根法。 +- 精度与停止条件:当 $|f(x)| < \varepsilon$(实现中取 pricesion = 1e-4)时返回当前近似值;输出时保留 10 位小数。 +- 复杂度:对每个测试用例,二分迭代次数为 O(log((R-L)/eps)),每步计算需要一次指数运算,故时间复杂度可认为是常数乘以二分迭代次数。 +- 注意事项:选择区间时要确保包含根;对边界和极端 b 的处理需验证区间是否足够大。 diff --git a/algorithm/2021F/lab_02/lab_02_C/lab_02_C.cpp b/algorithm/2021F/lab_02/lab_02_C/main.cpp similarity index 100% rename from algorithm/2021F/lab_02/lab_02_C/lab_02_C.cpp rename to algorithm/2021F/lab_02/lab_02_C/main.cpp diff --git a/algorithm/2021F/lab_02/lab_02_C/lab_02_C_test.cpp b/algorithm/2021F/lab_02/lab_02_C/test.cpp similarity index 93% rename from algorithm/2021F/lab_02/lab_02_C/lab_02_C_test.cpp rename to algorithm/2021F/lab_02/lab_02_C/test.cpp index 3d910870..d727db30 100644 --- a/algorithm/2021F/lab_02/lab_02_C/lab_02_C_test.cpp +++ b/algorithm/2021F/lab_02/lab_02_C/test.cpp @@ -7,8 +7,7 @@ #include #include #include - -#include "lab_02_C.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_02/lab_02_C/resource/"; } @@ -20,12 +19,9 @@ using std::tie; using std::cin; using std::cout; using std::tuple; -using std::vector; - -using Catch::Matchers::Equals; -using Catch::Matchers::UnorderedEquals; -using Catch::Matchers::Contains; - +using std::vector + ; +// 用wolframalpha 计算的 xe^(x/20)= b TEST_CASE("test case 1", "[test 02 C]") { const Catch::Approx target = Catch::Approx(0.9534862518).epsilon(0.01); CHECK(cal_detail(1) == target); diff --git a/algorithm/2021F/lab_02/lab_02_D/CMakeLists.txt b/algorithm/2021F/lab_02/lab_02_D/CMakeLists.txt index dce330ce..564aeae5 100644 --- a/algorithm/2021F/lab_02/lab_02_D/CMakeLists.txt +++ b/algorithm/2021F/lab_02/lab_02_D/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_02/lab_02_D/README.md b/algorithm/2021F/lab_02/lab_02_D/README.md new file mode 100644 index 00000000..b19fb7fe --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_D/README.md @@ -0,0 +1,48 @@ +# Problem D (Order 1424) + +## Description + +Given a nondecreasing sequence $a$ of $n$ integers $a_1, a_2, \dots, a_n$. + +Please find the number of pairs of indices $i, j$ (with $i < j$) such that $a_i + a_j$ is a power of two. + +## Input + +The 1st line is a positive integer $n$ ($1 \le n \le 100000$). + +The 2nd line contains $n$ integers: $a_1, a_2, \dots, a_n$. + +For each $a_i$ ($1 \le a_i \le 10^9$). + +## Output + +Print the number of pairs of indices $i, j$ ($i < j$) such that $a_i + a_j$ is a power of two. + +## Sample Input + +```text +4 +1 2 3 7 +``` + +## Sample Output + +```text +2 +``` + +## Hint + +The corresponding solutions to the sample are: $1 + 3 = 2^2$; $1 + 7 = 2^3$. + +## Solution / 思路解析 + +- 思路概述:题目要求统计下标对 $(i,j)$,使得 $i #include -#include "lab_02_D.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_02/lab_02_D/resource/"; } diff --git a/algorithm/2021F/lab_02/lab_02_E/CMakeLists.txt b/algorithm/2021F/lab_02/lab_02_E/CMakeLists.txt index c43d3c98..f6252ecc 100644 --- a/algorithm/2021F/lab_02/lab_02_E/CMakeLists.txt +++ b/algorithm/2021F/lab_02/lab_02_E/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_02/lab_02_E/README.md b/algorithm/2021F/lab_02/lab_02_E/README.md new file mode 100644 index 00000000..49476507 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_E/README.md @@ -0,0 +1,67 @@ +# lab02-e + +> cid: 1094, pid: 4 + +## Description + +Given two nondecreasing sequences $a$ and $b$, and their length are both $n$. + +What's the median after combining the subarray $a[l..r]$ and subarray $b[l..r]$? + +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$. + +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. + +For example: median([1,2,3,4]) = 2. + +### Input + +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. + +The second line contains $n$ integers: $a_1, a_2, \dots, a_n$. For each $a_i$ ($0\le a_i \le 10^9$). + +The third line contains $n$ integers: $b_1, b_2, \dots, b_n$. For each $b_i$ ($0\le b_i \le 10^9$). + +Then $T$ lines follow. Each line contains two integers $l$ and $r$ ($1\le l \le r \le n$) for a test case. + +### Output + +Output $T$ lines. Each line contains an integer $ans$, the median after combining the subarray $a[l..r]$ and subarray $b[l..r]$. + +### Sample Input + +``` log +5 2 +1 3 5 7 9 +2 3 4 5 6 +5 5 +1 5 +``` + +### Sample Output + +``` log +6 +4 +``` + +### HINT + +The corresponding solutions to the sample are: + +1) For query $(5,5)$: $a_5=9$, $b_5=6$, after combining is [9,6], the median is 6. + +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. + +## 复用信息 + +Contest 1093:CS203 2021 Fall Lab 02 Complexity + Binary Search +Contest 1094:CS217 2021 Fall Lab 02 Complexity + Binary Search +Contest 1162:CS203 2024 Fall Lab 1 + +## Algorithm Analysis (实现说明) + +- 思路: 对于每个查询 [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 小。 +- 实现要点: 主函数将输入转换为 0-based 索引, 对每个查询调用 kth_equal_len(aL,bL,k)。该函数对 i 做二分搜索,并在边界条件(i==0 或 j==0)处理访问。 +- 复杂度: 每次查询时间复杂度为 O(log k),总时间 O(T log n)。预处理/空间为 O(n)。 +- 边界情况: k=1 时直接比较两个元素;数组中存在重复值也能处理;所有索引访问都作好边界检查以避免越界。 diff --git a/algorithm/2021F/lab_02/lab_02_E/main.cpp b/algorithm/2021F/lab_02/lab_02_E/main.cpp new file mode 100644 index 00000000..a5b01e8e --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_E/main.cpp @@ -0,0 +1,141 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +//@Tag TODO +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_02_E{ +#endif + +using std::cin; +using std::tie; +using std::cout; +using std::list; +using std::sort; +using std::array; +using std::deque; +using std::queue; +using std::stack; +using std::tuple; +using std::string; +using std::vector; +using std::unordered_map; +using std::unordered_set; +using std::priority_queue; +static constexpr const char end{'\n'}; + +using num_t = int32_t; +using input_type = tuple, vector, vector>>; +using output_type = vector; + +inline input_type read(); + +output_type cal(const input_type &data); + +void output(const output_type &data); + +int main() { + auto input_data = read(); + auto output_data = cal(input_data); + output(output_data); + return 0; +} + +inline input_type read() { + num_t n{0}, T{0}; + std::cin >> n >> T; + vector A(n, -1), B(n, -1); + for (int32_t i{0}; i < n; i++) { + std::cin >> A[i]; + } + for (int32_t i{0}; i < n; i++) { + std::cin >> B[i]; + } + num_t tempa, tempb; + vector> pairs; + for (int32_t i{0}; i < T; ++i) { + std::cin >> tempa >> tempb; + pairs.emplace_back(tempa, tempb); + } + return std::make_tuple(A, B, pairs); +} + +output_type cal(const input_type &data) { + vector A, B; + vector> pairs; + tie(A, B, pairs) = data; + const int q = static_cast(pairs.size()); + vector ans; + ans.reserve(q); + + auto kth_equal_len = [&](int aL, int bL, int k) -> num_t { + // find k-th smallest (1-indexed) among A[aL..aL+k-1] and B[bL..bL+k-1] + int l = 0, r = k; + while (l <= r) { + int i = (l + r) >> 1; // take i from A + int j = k - i; // take j from B + // check boundaries before accessing + if (i > 0 && j < k && A[aL + i - 1] > B[bL + j]) { + r = i - 1; + } else if (j > 0 && i < k && B[bL + j - 1] > A[aL + i]) { + l = i + 1; + } else { + if (i == 0) return B[bL + j - 1]; + if (j == 0) return A[aL + i - 1]; + return std::max(A[aL + i - 1], B[bL + j - 1]); + } + } + return -1; // should not reach here + }; + + for (const auto &pr: pairs) { + int lq = static_cast(pr.first); + int rq = static_cast(pr.second); + // convert to 0-based + int aL = lq - 1; + int bL = lq - 1; + int k = rq - lq + 1; + ans.push_back(kth_equal_len(aL, bL, k)); + } + return ans; +} + +void output(const output_type &data) { + for (auto &&dat: data) { + cout << dat << end; + } +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_02/lab_02_E/lab_02_E_test.cpp b/algorithm/2021F/lab_02/lab_02_E/test.cpp similarity index 96% rename from algorithm/2021F/lab_02/lab_02_E/lab_02_E_test.cpp rename to algorithm/2021F/lab_02/lab_02_E/test.cpp index 0c9ba9af..56132088 100644 --- a/algorithm/2021F/lab_02/lab_02_E/lab_02_E_test.cpp +++ b/algorithm/2021F/lab_02/lab_02_E/test.cpp @@ -7,8 +7,7 @@ #include #include #include - -#include "lab_02_E.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_02/lab_02_E/resource/"; } @@ -32,7 +31,7 @@ TEST_CASE("test case 1", "[test 02 E]") { const vector> pairs{{5, 5}, {1, 5}}; const auto output_data = cal(std::make_tuple(A, B, pairs)); - CHECK_THAT(output_data, Equals({6, 4})); + CHECK_THAT(output_data, Equals({9, 5})); } TEST_CASE("test case with sequence", "[test 02 E]") { diff --git a/algorithm/2021F/lab_02/lab_02_F/CMakeLists.txt b/algorithm/2021F/lab_02/lab_02_F/CMakeLists.txt index 7bd14a82..3bd8bb2b 100644 --- a/algorithm/2021F/lab_02/lab_02_F/CMakeLists.txt +++ b/algorithm/2021F/lab_02/lab_02_F/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_02/lab_02_F/README.md b/algorithm/2021F/lab_02/lab_02_F/README.md new file mode 100644 index 00000000..49005528 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/README.md @@ -0,0 +1,77 @@ +# Problem F (Order 1426) + +## Description + +Given an $N \times N$ matrix $A$, whose element in the $i$-th row and $j$-th column $A[i][j]$ equals + +$$ +A[i][j] = i^2 + 12345 \times i + j^2 - 12345 \times j + i \times j +$$ + +Please find the $M$-th smallest element in the matrix. + + +## Input + +The 1st line is a positive integer $T$ ($1 \le T \le 10$) which is the number of test cases. + +Then $T$ lines follow. + +Each line has two integers $N$ ($1 \le N \le 50000$) and $M$ ($1 \le M \le N \times N$) for a test case. + +## Output + +Output $T$ lines. + +Each line has an integer $ans$, the $M$-th smallest element in the matrix. + +## Sample Input + +```text +2 +1 1 +2 1 +``` + +## Sample Output + +```text +3 +-12338 +``` + +## Hint + +The corresponding solutions to the sample are: + +(1) + +$$ +A[1][1] = 1^2 + 12345 \times 1 + 1^2 - 12345 \times 1 + 1 \times 1 = 3 +$$ + +(2) + +$$ +A[1][2] = 1^2 + 12345 \times 1 + 2^2 - 12345 \times 2 + 1 \times 2 = -12338 +$$ + +$$ +A[2][1]=22+12345 \times 2+12−12345 \times 1+2 \times 1=12352 +$$ + +$$ +A[2][2]=22+12345 \times 2+22−12345 \times 2+2 \times 2=12 +$$ + +So the smallest element is -12338 + +## Solution / 思路解析 + +- 思路概述:矩阵元素按公式 $A[i][j] = i^2 + 12345i + j^2 -12345j + i j$ 定义,要求第 $M$ 小元素。常见做法是对答案值 $X$ 进行二分(答案是某个整数或实数范围内的值),并用一个计数函数计算矩阵中小于等于 $X$ 的元素个数 cnt。如果 cnt >= M,则可将上界收缩,否则下界上移。最终二分求得第 M 小元素的值。 +- 计数函数实现要点(代码对应):对每一行 i,关于 j 的不等式 $A[i][j] \le X$ 是一个关于 j 的二次不等式。把它化为标准二次形式后,计算判别式并求解实根区间 $[L,R]$,然后取整并交到 $[1,N]$ 区间内,令该行对总计数贡献为 $\max(0, R-L+1)$。遍历所有 i 累加计数得到 cnt。 +- 复杂度:每次二分需要对 N 行做一次二次方程求根,复杂度 O(N)(每行常数时间,主要是开方操作)。二分迭代次数为 O(log RANGE)(RANGE 为值域长度),整体复杂度约 O(N log RANGE)。空间 O(1)(常数额外空间)。 +- 精度与整型注意:实现中使用 64 位整数和 long double 来计算判别式与根,并对上下界做向上/向下取整以得到整数列范围,且提前剪枝(D<0)以提高稳定性。 +- 边界与注意事项: + - 确保对极端 X 值(非常大或非常小)时判别式不会产生误差;使用 long double 并在转换为整数时加减一个小量(如 1e-12)来抵消浮点误差。 + - 当 N 较大(例如 50000)时,count_leq 的每次遍历仍是可行的,但注意总二分次数与常数因子会影响运行时间。 diff --git a/algorithm/2021F/lab_02/lab_02_F/lab_02_F.cpp b/algorithm/2021F/lab_02/lab_02_F/lab_02_F.cpp deleted file mode 100644 index b0505237..00000000 --- a/algorithm/2021F/lab_02/lab_02_F/lab_02_F.cpp +++ /dev/null @@ -1,87 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later -// SPDX-FileCopyrightText: 2020-2025 nanoseeds -//@Tag TODO -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef ALGORITHM_TEST_MACRO -namespace lab_02_F{ -#endif - -using std::cin; -using std::tie; -using std::cout; -using std::list; -using std::sort; -using std::array; -using std::deque; -using std::queue; -using std::stack; -using std::tuple; -using std::string; -using std::vector; -using std::unordered_map; -using std::unordered_set; -using std::priority_queue; -static constexpr const char end{'\n'}; - -using num_t = int32_t; -using input_type = tuple; -using output_type = num_t; - -inline input_type read(); - -output_type cal(input_type data); - -void output(const output_type &data); - -int main() { - auto input_data = read(); - auto output_data = cal(input_data); - output(output_data); - return 0; -} - -inline input_type read() { - num_t a{0}, b{0}; - std::cin >> a >> b; - return std::make_tuple(a, b); -} - -output_type cal(input_type data) { - num_t a{0}, b{0}; - tie(a, b) = data; - num_t c = a + b; - return c; -} - -void output(const output_type &data) { - cout << data << end; -} - -static const auto faster_streams = [] { - srand(time(nullptr)); - // use time to init the random seed - std::ios::sync_with_stdio(false); - std::istream::sync_with_stdio(false); - std::ostream::sync_with_stdio(false); - std::cin.tie(nullptr); - std::cout.tie(nullptr); - // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. - return 0; -}(); -#ifdef ALGORITHM_TEST_MACRO -} -#endif diff --git a/algorithm/2021F/lab_02/lab_02_F/lab_02_F_test.cpp b/algorithm/2021F/lab_02/lab_02_F/lab_02_F_test.cpp deleted file mode 100644 index efde1036..00000000 --- a/algorithm/2021F/lab_02/lab_02_F/lab_02_F_test.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later -// SPDX-FileCopyrightText: 2020-2025 nanoseeds -#ifdef ALGORITHM_TEST_MACRO - -#include -#include -#include -#include -#include - -#include "lab_02_F.cpp" - -std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_02/lab_02_F/resource/"; } - -const std::string CS203_redirect::file_paths = getFilePath(); - -namespace lab_02_F { - -using std::tie; -using std::cin; -using std::cout; -using std::tuple; -using std::vector; - -using Catch::Matchers::Equals; -using Catch::Matchers::UnorderedEquals; -using Catch::Matchers::Contains; - -TEST_CASE("test case 1", "[test 02 F]") { - const auto output_data = cal(std::make_tuple(114, 514)); - CHECK(output_data == 628); - CHECK(1 + 2 == 3); - vector vec{2, 7, 11, 15}; - SECTION("CHECK_THAT 1") { - CHECK_THAT(vec, Contains({2})); - }SECTION("vec matcher") { - CHECK_THAT(vec, UnorderedEquals({15, 11, 7, 2})); - } -} -// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` -TEST_CASE("test case with sequence", "[test 02 F][.]") { - CS203_sequence sequence{1, 0, 0}; // // 基础设定,[1,1] - sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in - sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out - sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out - const auto files_name = sequence.get_files(true); - // 获取一个std::tuple , - // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. - for (const auto &file_name: files_name) { - string datain, dataout, testout; // 声明 - tie(datain, dataout, testout) = file_name; // 解包 - { - const CS203_redirect cr{datain, testout}; // 重定向输入,输出 - main(); - // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 - } - CHECK(compareFiles(testout, dataout)); - } -} -} -#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_02/lab_02_F/main.cpp b/algorithm/2021F/lab_02/lab_02_F/main.cpp new file mode 100644 index 00000000..68737c6c --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/main.cpp @@ -0,0 +1,109 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +// Problem F: find M-th smallest element in A where +// A[i][j] = i^2 + 12345*i + j^2 -12345*j + i*j +// Approach: binary search on value X, count number of pairs (i,j) with A[i][j] <= X + +#include +#include +#include +#include +#include + +#ifdef ALGORITHM_TEST_MACRO +namespace lab_02_F { +#endif + +using std::cin; +using std::cout; +using std::vector; +using std::int64_t; +using std::int32_t; +static constexpr const char end{'\n'}; + +// count number of pairs (i,j) with 1<=i,j<=N and A[i][j] <= X +static inline int64_t count_leq(int N, int64_t X) { + int64_t cnt = 0; + for (int i = 1; i <= N; ++i) { + int64_t B = int64_t(i) - int64_t(12345); + int64_t C = int64_t(i) * int64_t(i) + int64_t(12345) * int64_t(i) - X; + long double D = (long double) B * (long double) B - 4.0L * (long double) C; + if (D < 0) continue; + long double sd = std::sqrt(D); + long double r1 = (-(long double) B - sd) / 2.0L; + long double r2 = (-(long double) B + sd) / 2.0L; + auto L = (int64_t) std::ceil(r1 - 1e-12L); + auto R = (int64_t) std::floor(r2 + 1e-12L); + if (R < 1 || L > N) continue; + if (L < 1) L = 1; + if (R > N) R = N; + if (R >= L) cnt += (R - L + 1); + if (cnt > (int64_t(1) << 62)) return cnt; + } + return cnt; +} + +// ---- Input / Process / Output style ---- +using input_type = vector >; // (N, M) +using output_type = vector; + +static input_type read_input() { + int T; + if (!(cin >> T)) return {}; + input_type in; + in.reserve(T); + for (int i = 0; i < T; ++i) { + int N; + int64_t M; + cin >> N >> M; + in.emplace_back(N, M); + } + return in; +} + +static output_type process(const input_type &in) { + output_type ans; + ans.reserve(in.size()); + for (auto &pr: in) { + int N = pr.first; + int64_t M = pr.second; + int64_t lo = std::numeric_limits::min() / 4; + int64_t hi = std::numeric_limits::max() / 4; + while (lo < hi) { + int64_t mid = lo + ((hi - lo) >> 1); + int64_t cnt = count_leq(N, mid); + if (cnt >= M) hi = mid; + else lo = mid + 1; + } + ans.push_back(lo); + } + return ans; +} + +static void write_output(const output_type &out) { + for (auto v: out) { cout << v << end; } +} + +int main() { + auto input = read_input(); + auto output = process(input); + write_output(output); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/01.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/01.data.in new file mode 100644 index 00000000..9827e27e --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/01.data.in @@ -0,0 +1,3 @@ +2 +1 1 +2 1 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/01.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/01.data.out new file mode 100644 index 00000000..ac88be52 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/01.data.out @@ -0,0 +1,2 @@ +3 +-12338 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/02.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/02.data.in new file mode 100644 index 00000000..20478c63 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/02.data.in @@ -0,0 +1,2 @@ +1 +1 1 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/02.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/02.data.out new file mode 100644 index 00000000..00750edc --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/02.data.out @@ -0,0 +1 @@ +3 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/03.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/03.data.in new file mode 100644 index 00000000..0bdc75bb --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/03.data.in @@ -0,0 +1,2 @@ +1 +2 1 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/03.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/03.data.out new file mode 100644 index 00000000..88a7900e --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/03.data.out @@ -0,0 +1 @@ +-12338 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/04.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/04.data.in new file mode 100644 index 00000000..c0fe29e3 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/04.data.in @@ -0,0 +1,2 @@ +1 +2 4 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/04.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/04.data.out new file mode 100644 index 00000000..1295f05c --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/04.data.out @@ -0,0 +1 @@ +12352 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/05.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/05.data.in new file mode 100644 index 00000000..b620873c --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/05.data.in @@ -0,0 +1,3 @@ +2 +3 1 +3 9 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/05.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/05.data.out new file mode 100644 index 00000000..5d0c3379 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/05.data.out @@ -0,0 +1,2 @@ +-24677 +24703 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/06.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/06.data.in new file mode 100644 index 00000000..2121b1db --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/06.data.in @@ -0,0 +1,2 @@ +1 +10 50 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/06.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/06.data.out new file mode 100644 index 00000000..78eb67ce --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/06.data.out @@ -0,0 +1 @@ +75 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/07.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/07.data.in new file mode 100644 index 00000000..34dd3844 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/07.data.in @@ -0,0 +1,2 @@ +1 +100 1 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/07.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/07.data.out new file mode 100644 index 00000000..e8d3e82f --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/07.data.out @@ -0,0 +1 @@ +-1212054 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/08.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/08.data.in new file mode 100644 index 00000000..fd6b5d59 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/08.data.in @@ -0,0 +1,2 @@ +1 +100 10000 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/08.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/08.data.out new file mode 100644 index 00000000..5e80e63a --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/08.data.out @@ -0,0 +1 @@ +1232256 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/09.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/09.data.in new file mode 100644 index 00000000..b252b6b9 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/09.data.in @@ -0,0 +1,2 @@ +1 +500 125000 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/09.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/09.data.out new file mode 100644 index 00000000..83e38f92 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/09.data.out @@ -0,0 +1 @@ +243964 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/10.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/10.data.in new file mode 100644 index 00000000..d48b6b12 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/10.data.in @@ -0,0 +1,4 @@ +3 +1 1 +2 2 +3 5 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/10.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/10.data.out new file mode 100644 index 00000000..ed6f6cdb --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/10.data.out @@ -0,0 +1,3 @@ +3 +3 +12 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/11.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/11.data.in new file mode 100644 index 00000000..f12d8878 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/11.data.in @@ -0,0 +1,2 @@ +1 +50000 2500000000 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/11.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/11.data.out new file mode 100644 index 00000000..7806b3dc --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/11.data.out @@ -0,0 +1 @@ +7500000000 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/12.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/12.data.in new file mode 100644 index 00000000..ff544720 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/12.data.in @@ -0,0 +1,3 @@ +2 +5 10 +5 1 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/12.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/12.data.out new file mode 100644 index 00000000..7accec01 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/12.data.out @@ -0,0 +1,2 @@ +-12284 +-49349 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/13.data.in b/algorithm/2021F/lab_02/lab_02_F/resource/13.data.in new file mode 100644 index 00000000..cd5c7a32 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/13.data.in @@ -0,0 +1,2 @@ +1 +50 1250 diff --git a/algorithm/2021F/lab_02/lab_02_F/resource/13.data.out b/algorithm/2021F/lab_02/lab_02_F/resource/13.data.out new file mode 100644 index 00000000..3e4bffc1 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/resource/13.data.out @@ -0,0 +1 @@ +1875 diff --git a/algorithm/2021F/lab_02/lab_02_F/test.cpp b/algorithm/2021F/lab_02/lab_02_F/test.cpp new file mode 100644 index 00000000..b2ad717d --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_F/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_02/lab_02_F/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_02_F { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence", "[test 02 F]") { + CS203_sequence sequence{1, 13, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_02/lab_02_G/CMakeLists.txt b/algorithm/2021F/lab_02/lab_02_G/CMakeLists.txt new file mode 100644 index 00000000..768dc1e2 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER G) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_02/lab_02_G/README.md b/algorithm/2021F/lab_02/lab_02_G/README.md new file mode 100644 index 00000000..bed83ffb --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/README.md @@ -0,0 +1,42 @@ +# Problem G (Order 1427) + +## Description + +Given an array $a$ of length $n$. You need to find a subarray $a[l..r]$ with length at least $k$ that has the largest median. + +A median in an array of length $x$ is the $\left\lfloor\frac{x+1}{2}\right\rfloor$-th smallest element. For example: $\mathrm{median}([1,2,3,4]) = 2$, $\mathrm{median}([3,2,1]) = 2$, $\mathrm{median}([2,1,2,1]) = 1$. + +## Input + +The 1st line contains two integers $n$ and $k$ ($1 \le k \le n \le 200000$). The 2nd line has $n$ integers: $a_1, a_2, \dots, a_n$. For each $a_i$ ($0 \le a_i \le 10^9$). + +## Output + +Output one integer $m$ — the maximum median you can get. + +## Sample Input + +```text +5 3 +1 2 3 2 1 +``` + +## Sample Output + +```text +2 +``` + +## Hint + +The max median 2 is found from the subarray [2, 3, 2]. + +## Solution / 思路解析 + +- 思路概述:要找到长度至少为 $k$ 的子数组中能取得的最大中位数,可用二分答案(枚举候选中位数 $x$)+判定函数的方法:判断是否存在一个长度至少为 $k$ 的子数组,其中位数不小于 $x$。对 $x$ 做二分,找到最大的可行值即为答案。 +- 判定函数(代码实现要点):把原数组元素映射为 +1(若 $a_i \ge x$)或 -1(若 $a_i < x$),计算前缀和 pref。若存在区间长度至少为 $k$,使得区间和大于 0,则说明该区间中 “不小于 $x$” 的元素严格多于“小于 $x$”的元素,从而中位数至少为 $x$。实现通过维护最小前缀值(到位置 i-k)并检查 pref[i] - min_pref > 0 来完成判定。 +- 二分搜索:对答案的搜索区间可设为题面值域(代码中用 [0, 1e9]),在每步取上中位数向上取整的方式推进(`mid = lo + (hi-lo+1)>>1`),当判定函数为真时把 lo 提升到 mid,否则把 hi 下调到 mid-1,循环结束 lo 即为答案。 +- 复杂度:判定函数为 O(n),二分搜索约 O(log V),总体 O(n log V)。空间 O(n) 用于前缀和数组。 +- 边界与注意事项: + - 要确保映射与前缀和的定义满足中位数判定的严格性(这里用 +1/-1,并用严格大于 0 判断);对于偶数长度的中位数定义(题中定义为 floor((len+1)/2))该映射是正确的。 + - 注意输入值域(这里在 0..1e9)和 int32 类型的安全使用;实现中用 int32_t 存储并操作前缀和(累加范围在 [-n,n] 内),安全。 diff --git a/algorithm/2021F/lab_02/lab_02_G/main.cpp b/algorithm/2021F/lab_02/lab_02_G/main.cpp new file mode 100644 index 00000000..9f17261b --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/main.cpp @@ -0,0 +1,86 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +// Problem G: max median of any subarray with length >= k + +#include +#include +#include +#include + +#ifdef ALGORITHM_TEST_MACRO +namespace lab_02_G { +#endif + +using std::cin; +using std::cout; +using std::vector; +using std::int32_t; +using std::int64_t; +static constexpr const char end{'\n'}; + +struct Input { + int32_t n; + int32_t k; + vector a; +}; + +static Input read_input() { + Input in; + cin >> in.n >> in.k; + in.a.assign(in.n, 0); + for (int32_t i = 0; i < in.n; ++i) cin >> in.a[i]; + return in; +} + +// check if there exists subarray length >= k with median >= x +static bool check_median_at_least(const vector &a, int32_t k, int32_t x) { + const int n = static_cast(a.size()); + // prefix sums of transformed values: +1 if a[i]>=x, else -1 + vector pref(n + 1, 0); + for (int i = 1; i <= n; ++i) { + pref[i] = pref[i-1] + (a[i-1] >= x ? 1 : -1); + } + int32_t min_pref = 0; // minimal prefix up to index i-k + for (int i = k; i <= n; ++i) { + // update min_pref with prefix at i-k + min_pref = std::min(min_pref, pref[i - k]); + if (pref[i] - min_pref > 0) return true; + } + return false; +} + +static int32_t solve(const Input &in) { + int32_t lo = 0; + int32_t hi = 1000000000; // per constraints + while (lo < hi) { + int32_t mid = lo + ((hi - lo + 1) >> 1); + if (check_median_at_least(in.a, in.k, mid)) lo = mid; + else hi = mid - 1; + } + return lo; +} + +static void write_output(int32_t ans) { + cout << ans << end; +} + +int main() { + auto in = read_input(); + auto ans = solve(in); + write_output(ans); + return 0; +} +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/.gitignore b/algorithm/2021F/lab_02/lab_02_G/resource/.gitignore new file mode 100644 index 00000000..95488964 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/.gitignore @@ -0,0 +1,3 @@ +!*.data.in +!*.data.out +*.test.out diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/1.data.in b/algorithm/2021F/lab_02/lab_02_G/resource/1.data.in new file mode 100644 index 00000000..2d1ae650 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/1.data.in @@ -0,0 +1,2 @@ +5 3 +1 2 3 2 1 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/1.data.out b/algorithm/2021F/lab_02/lab_02_G/resource/1.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/1.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/2.data.in b/algorithm/2021F/lab_02/lab_02_G/resource/2.data.in new file mode 100644 index 00000000..2d1ae650 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/2.data.in @@ -0,0 +1,2 @@ +5 3 +1 2 3 2 1 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/2.data.out b/algorithm/2021F/lab_02/lab_02_G/resource/2.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/2.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/3.data.in b/algorithm/2021F/lab_02/lab_02_G/resource/3.data.in new file mode 100644 index 00000000..8ccff4d1 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/3.data.in @@ -0,0 +1,2 @@ +6 1 +0 0 1000000000 5 5 3 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/3.data.out b/algorithm/2021F/lab_02/lab_02_G/resource/3.data.out new file mode 100644 index 00000000..770fdcfb --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/3.data.out @@ -0,0 +1 @@ +1000000000 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/4.data.in b/algorithm/2021F/lab_02/lab_02_G/resource/4.data.in new file mode 100644 index 00000000..699fabc2 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/4.data.in @@ -0,0 +1,2 @@ +7 7 +7 1 5 3 9 2 4 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/4.data.out b/algorithm/2021F/lab_02/lab_02_G/resource/4.data.out new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/4.data.out @@ -0,0 +1 @@ +4 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/5.data.in b/algorithm/2021F/lab_02/lab_02_G/resource/5.data.in new file mode 100644 index 00000000..71509390 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/5.data.in @@ -0,0 +1,2 @@ +8 3 +2 2 2 2 2 2 2 2 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/5.data.out b/algorithm/2021F/lab_02/lab_02_G/resource/5.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/5.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/6.data.in b/algorithm/2021F/lab_02/lab_02_G/resource/6.data.in new file mode 100644 index 00000000..cd408e50 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/6.data.in @@ -0,0 +1,2 @@ +10 4 +1 2 3 4 5 6 7 8 9 10 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/6.data.out b/algorithm/2021F/lab_02/lab_02_G/resource/6.data.out new file mode 100644 index 00000000..45a4fb75 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/6.data.out @@ -0,0 +1 @@ +8 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/7.data.in b/algorithm/2021F/lab_02/lab_02_G/resource/7.data.in new file mode 100644 index 00000000..d8691427 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/7.data.in @@ -0,0 +1,2 @@ +12 5 +5 5 5 6 7 1000000000 999999999 0 3 6 7 8 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/7.data.out b/algorithm/2021F/lab_02/lab_02_G/resource/7.data.out new file mode 100644 index 00000000..7f8f011e --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/7.data.out @@ -0,0 +1 @@ +7 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/8.data.in b/algorithm/2021F/lab_02/lab_02_G/resource/8.data.in new file mode 100644 index 00000000..065b1b50 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/8.data.in @@ -0,0 +1,2 @@ +10 6 +10 9 8 7 6 5 4 3 2 1 diff --git a/algorithm/2021F/lab_02/lab_02_G/resource/8.data.out b/algorithm/2021F/lab_02/lab_02_G/resource/8.data.out new file mode 100644 index 00000000..7f8f011e --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/resource/8.data.out @@ -0,0 +1 @@ +7 diff --git a/algorithm/2021F/lab_02/lab_02_G/test.cpp b/algorithm/2021F/lab_02/lab_02_G/test.cpp new file mode 100644 index 00000000..cdcaf816 --- /dev/null +++ b/algorithm/2021F/lab_02/lab_02_G/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_02/lab_02_G/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_02_G { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence", "[test 02 G]") { + CS203_sequence sequence{1, 8, 1}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_03/CMakeLists.txt b/algorithm/2021F/lab_03/CMakeLists.txt index 42d34022..2df387a9 100644 --- a/algorithm/2021F/lab_03/CMakeLists.txt +++ b/algorithm/2021F/lab_03/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -set(dependencies A B C D E F) +set(dependencies A B C D E F G) foreach (elementName IN LISTS dependencies) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${elementName}) endforeach () diff --git a/algorithm/2021F/lab_03/README.md b/algorithm/2021F/lab_03/README.md new file mode 100644 index 00000000..d15e9de1 --- /dev/null +++ b/algorithm/2021F/lab_03/README.md @@ -0,0 +1,37 @@ +--- +SPDX-License-Identifier: CC-BY-NC-SA-4.0 +--- + +# Contest1095 - CS203 2021 Fall Lab 03 Sorting + +> cid: 1096 + +Welcome to CS203 2021 Fall Lab 03! Enjoy this Lab! + +There are six problems for you to solve. + +Score: + +- A: 10 +- B: 15/10 +- C: 15/10 +- D: 20/15 +- E: 20/15 +- F: 20/20 +- G: undefined/20 + +Reading the samples and hints carefully can help you understand the problem. + +## Problems + +| Problem | problem id | +|---:|---:| +| A | 1428 | +| B | 1429 | +| C | 1430 | +| D | 1431 | +| E | 1432 | +| F | 1433 | +| G | 1434 | + +B, E, F被复用 diff --git a/algorithm/2021F/lab_03/cs203.submit.csv b/algorithm/2021F/lab_03/cs203.submit.csv new file mode 100644 index 00000000..bbfd3695 --- /dev/null +++ b/algorithm/2021F/lab_03/cs203.submit.csv @@ -0,0 +1,8 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 268, 72, 640, 332, 1, 5, 90, 113, 1521, 33, 227, 1261 +B, 277, 3, 342, 314, 10, 26, 82, 136, 1190, 26, 251, 913 +C, 240, 11, 609, 14, 1, 34, 59, 968, 16, 194, 758 +D, 247, 81, 188, 2, 34, 46, 598, 10, 118, 470 +E, 224, 1, 401, 265, 2, 9, 31, 45, 978, 16, 187, 775 +F, 215, 1750, 225, 3, 1, 240, 99, 2533, 30, 573, 1930 +Total, 1471, 87, 3823, 1338, 18, 42, 511, 498, 7788, 131, 1550, 6107 diff --git a/algorithm/2021F/lab_03/cs217.submit.csv b/algorithm/2021F/lab_03/cs217.submit.csv new file mode 100644 index 00000000..595e1bf5 --- /dev/null +++ b/algorithm/2021F/lab_03/cs217.submit.csv @@ -0,0 +1,9 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 32, 1, 28, 15, 3, 1, 80, 1, 25, 54 +B, 30, 1, 21, 15, 1, 4, 4, 76, 40, 36 +C, 28, 36, 1, 65, 19, 46 +D, 38, 8, 7, 1, 1, 1, 56, 32, 24 +E, 34, 29, 18, 1, 2, 3, 87, 6, 31, 50 +F, 27, 93, 8, 13, 4, 145, 50, 95 +G, 32, 63, 6, 8, 3, 112, 52, 60 +Total, 221, 2, 278, 69, 2, 1, 32, 16, 621, 7, 249, 365 diff --git a/algorithm/2021F/lab_03/lab_03_A/CMakeLists.txt b/algorithm/2021F/lab_03/lab_03_A/CMakeLists.txt index 354751e1..40897f09 100644 --- a/algorithm/2021F/lab_03/lab_03_A/CMakeLists.txt +++ b/algorithm/2021F/lab_03/lab_03_A/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_03/lab_03_A/README.md b/algorithm/2021F/lab_03/lab_03_A/README.md new file mode 100644 index 00000000..c7908db4 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_A/README.md @@ -0,0 +1,72 @@ +--- +SPDX-License-Identifier: CC-BY-NC-SA-4.0 +--- + +# lab_03_A + +## Description + +Let $A$ and $B$ be two non-decreasing arrays of sizes $n$ and $m$ respectively. + +We form $C = \{A_1, A_2, \dots, A_n, B_1, B_2, \dots, B_m\}$. A pair $(C_i, C_j)$ is a reverse pair when $C_i > C_j$ and $i < j$. + +For each test case compute two outputs. First, the number of reverse pairs in $C$. + +Second, output the merged non-decreasing sequence $C$. + +## Input + +The first line contains an integer $T$ ($1 \le T \le 10$). Each test case contains three lines. + +The first line of a test case contains two integers $n$ and $m$. + +The second line contains $n$ integers $A_1, A_2, \dots, A_n$. + +The third line contains $m$ integers $B_1, B_2, \dots, B_m$. + +Constraints: $1 \le n, m \le 10^5$ and $0 \le A_i, B_j \le 10^9$. + +## Output + +For each test case print two lines. The first line is the number of reverse pairs in $C$. + +The second line is the merged sequence $C$: $C_1, C_2, \dots, C_{n+m}$. + +## Sample + +### Sample Input + +```text +2 +2 4 +2 3 +1 2 3 4 +2 2 +3 4 +1 2 +``` + +### Sample Output + +```text +3 +1 2 2 3 3 4 4 +1 +2 3 4 1 2 +``` + +## Notes + +This problem can be solved by merging the two sorted arrays with a two-pointer method. + +While merging, count how many elements from the remaining left part are greater than the current element taken from the right part to accumulate cross-inversions. + +## Analysis + +该解法在合并两个非递减数组的同时统计跨数组的逆序对。 + +做法是将左数组和右数组拷贝到同一个工作缓冲区,然后用双指针进行归并;当从左半部分取出一个元素时,增加当前已被取出的右半部分元素数量,作为该元素所贡献的逆序对个数。 + +合并后的值保存在缓冲区中,最终输出合并的非递减序列以及逆序对总数。 + +此方法对每个测试用例的时间复杂度为 $O(n+m)$,需要 $O(n+m)$ 的额外内存用于临时缓冲区。 diff --git a/algorithm/2021F/lab_03/lab_03_A/lab_03_A.cpp b/algorithm/2021F/lab_03/lab_03_A/main.cpp similarity index 81% rename from algorithm/2021F/lab_03/lab_03_A/lab_03_A.cpp rename to algorithm/2021F/lab_03/lab_03_A/main.cpp index 7e584667..b4ff79f3 100644 --- a/algorithm/2021F/lab_03/lab_03_A/lab_03_A.cpp +++ b/algorithm/2021F/lab_03/lab_03_A/main.cpp @@ -1,24 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: 2020-2025 nanoseeds -/* - * @题目描述 - * 在____内, 如果数组C中,有 i,j ∈N+, i < j, C[i]>C[j], 则 (C[i],C[j])为一个逆序对 - * 给出两个非递减数组,长度为ν的数组D与长度为μ的数组E - * 首先,请给出, C{D.begin(),D.end(),E.begin(),E.end()}所组成的逆序对 - * 其次, 给出非递减数组C本身 - * 如果没有IDEA的话,可以参考lecture3的口口页 - * @输入 - * 第一行给出一个int32_t τ ∈ [1,10],代表测试样例数 - * 接下来对每个测试用例 - * 第一行有两个int32_t ν,μ 代表D,E两个非递减数组的长度 - * 第二行有 ν 个int32_t, {D.begin(),D.end()} - * 第三行有 μ 个int32_t, {E.begin(),E.end()} - * ν ∈ [1,10^5], μ ∈ [1,10^5] ,D,E中的每个元素都 ∈ [1,10^9] - * @输出 - * 对每个测试用例来说 - * 第一行输出逆序对数量 - * 第二行输出排好序的C - * */ //@Tag Done #include #include diff --git a/algorithm/2021F/lab_03/lab_03_A/lab_03_A_test.cpp b/algorithm/2021F/lab_03/lab_03_A/test.cpp similarity index 98% rename from algorithm/2021F/lab_03/lab_03_A/lab_03_A_test.cpp rename to algorithm/2021F/lab_03/lab_03_A/test.cpp index dab569ba..7a47c13f 100644 --- a/algorithm/2021F/lab_03/lab_03_A/lab_03_A_test.cpp +++ b/algorithm/2021F/lab_03/lab_03_A/test.cpp @@ -12,7 +12,7 @@ #include #include -#include "lab_03_A.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_03/lab_03_A/resource/"; } diff --git a/algorithm/2021F/lab_03/lab_03_B/CMakeLists.txt b/algorithm/2021F/lab_03/lab_03_B/CMakeLists.txt index c490830a..dac0839a 100644 --- a/algorithm/2021F/lab_03/lab_03_B/CMakeLists.txt +++ b/algorithm/2021F/lab_03/lab_03_B/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_03/lab_03_B/README.md b/algorithm/2021F/lab_03/lab_03_B/README.md new file mode 100644 index 00000000..6d444589 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_B/README.md @@ -0,0 +1,47 @@ +--- +SPDX-License-Identifier: CC-BY-NC-SA-4.0 +--- + +# lab_03_B — Median (double form) + +## Description + +Given an array α of length ν, output the "median in double form" defined as: + +- If ν is even: return (α[ν/2 - 1] + α[ν/2]) +- If ν is odd: return 2 * α[ν/2] + +The array is 0-indexed in the definition above. + +The result is an integer (not a floating point number): when ν is odd we return twice the middle element, when ν is even we return the sum of the two middle elements. + +## Input + +The first line contains an integer n (2 ≤ n ≤ 5*10^6). + +The second line contains n integers (each in range [0, 2^31 - 1]). + +## Output + +Output a single integer: the median in the double form defined above. + +## Notes + +- Be careful with overflow: 2 * int32_t can overflow a 32-bit signed integer. Use 64-bit integers (e.g., `int64_t`) when computing the result. + +## Analysis + +该程序使用自定义的归并排序对输入数组进行排序,以便可以确定性地访问中间元素。 + +排序完成后,当数组长度为偶数时返回中间两个元素之和;当长度为奇数时返回中间元素的两倍,从而实现“double median”的定义。 + +所有计算使用 64 位整数,以避免对 32 位整数执行加倍或相加时发生溢出。 + +归并排序为主要耗时步骤,时间复杂度为 $O(n\log n)$,并需要 $O(n)$ 的辅助内存作为临时缓冲区。 + +## 复用信息 + +- Contest 1095:CS203 2021 Fall Lab 03 Sorting +- Contest 1096:CS217 2021 Fall Lab 03 Sorting +- Contest 1137:CS203 2023 Fall Lab 2 Sorting +- Contest 1187:CS203 2025 Fall Lab 2 Sorting diff --git a/algorithm/2021F/lab_03/lab_03_B/lab_03_B.cpp b/algorithm/2021F/lab_03/lab_03_B/main.cpp similarity index 85% rename from algorithm/2021F/lab_03/lab_03_B/lab_03_B.cpp rename to algorithm/2021F/lab_03/lab_03_B/main.cpp index a0cd5b2d..e0ed633c 100644 --- a/algorithm/2021F/lab_03/lab_03_B/lab_03_B.cpp +++ b/algorithm/2021F/lab_03/lab_03_B/main.cpp @@ -1,25 +1,8 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: 2020-2025 nanoseeds -/* - * @题目描述 - * 数组α具有ν个元素,请输出数组a `中位数的double形式` - * `中位数的double形式` 定义为, - * match (ν % 2) { - * 0 => { return (α[ν/2-1]+α[ν/2]); } - * 1 => { return 2*α[ν/2]; } - * }; - * @输入 - * 第一行输入 int32_t n, 大于1,小于5*10^6 - * 第二行有n个int32_t, [0,2^31-1] - * @输出 - * 一个 `中位数的double形式` - * @解析,此处坑点在于 int32_t *2会爆掉,所以都需要使用int64_t - * */ + //@Tag Done -#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") -#pragma GCC optimize("inline-small-functions") -#pragma GCC optimize("-finline-small-functions") -#pragma GCC target("mmx") + #include #include @@ -27,7 +10,12 @@ #include #include -#ifdef ALGORITHM_TEST_MACRO +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else namespace lab_03_B{ #endif diff --git a/algorithm/2021F/lab_03/lab_03_B/lab_03_B_test.cpp b/algorithm/2021F/lab_03/lab_03_B/test.cpp similarity index 98% rename from algorithm/2021F/lab_03/lab_03_B/lab_03_B_test.cpp rename to algorithm/2021F/lab_03/lab_03_B/test.cpp index 7fa0a73f..a74cd920 100644 --- a/algorithm/2021F/lab_03/lab_03_B/lab_03_B_test.cpp +++ b/algorithm/2021F/lab_03/lab_03_B/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_03_B.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_03/lab_03_B/resource/"; } diff --git a/algorithm/2021F/lab_03/lab_03_C/CMakeLists.txt b/algorithm/2021F/lab_03/lab_03_C/CMakeLists.txt index 5de3f24f..f07d2e4c 100644 --- a/algorithm/2021F/lab_03/lab_03_C/CMakeLists.txt +++ b/algorithm/2021F/lab_03/lab_03_C/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_03/lab_03_C/README.md b/algorithm/2021F/lab_03/lab_03_C/README.md new file mode 100644 index 00000000..b00ec478 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_C/README.md @@ -0,0 +1,64 @@ +--- +SPDX-License-Identifier: CC-BY-NC-SA-4.0 +--- + +# lab_03_C + +## Description + +Given an unsorted sequence, sort it using insertion sort and selection sort respectively. + +Compare which algorithm performs fewer operations. + +We count both "swap two numbers" and "compare two numbers" as one operation each. + +The algorithm with fewer total operations is considered better. + +It is guaranteed that the number of operations differs between the two algorithms for all test cases. + +## Input + +The first line contains an integer $T$ ($1 \le T \le 10$), the number of test cases. + +For each test case the first line contains an integer $n$ ($2 \le n \le 10^3$), followed by $n$ integers. + +## Output + +For each test case, output two lines. The first line is the sorted array in ascending order. + +The second line is the winner message. + +Print "Insertion Sort wins!" if insertion sort uses fewer operations. + +Otherwise print "Selection Sort wins!". + +## Analysis + +实现通过分别模拟插入排序和选择排序的操作计数来比较两者的开销。 + +插入排序在每次将当前元素向前移动时,对每次比较计数一次;当发生相邻元素交换时再计数一次交换操作。 + +选择排序在每次扫描后缀寻找最小值时,对每次比较计数一次;若找到的最小值需要与当前位置交换,则计数一次交换操作。 + +在得到两者的操作计数后,程序用 `std::sort` 对序列进行排序以打印最终结果,并根据计数比较决定胜者。 + +两种计数例程的最坏情况时间复杂度均为 $O(n^2)$,额外空间开销仅为对输入序列的临时拷贝($O(n)$)。 + +## Sample + +### Sample Input + +```text +2 +3 1 3 2 +3 3 2 1 +``` + +### Sample Output + +```text +1 2 3 +Insertion Sort wins! +1 2 3 +Selection Sort wins! +``` diff --git a/algorithm/2021F/lab_03/lab_03_C/lab_03_C.cpp b/algorithm/2021F/lab_03/lab_03_C/main.cpp similarity index 67% rename from algorithm/2021F/lab_03/lab_03_C/lab_03_C.cpp rename to algorithm/2021F/lab_03/lab_03_C/main.cpp index fd6f742b..a227a82d 100644 --- a/algorithm/2021F/lab_03/lab_03_C/lab_03_C.cpp +++ b/algorithm/2021F/lab_03/lab_03_C/main.cpp @@ -1,24 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: 2020-2025 nanoseeds -/* - *@题目描述 - * 输入为一个无序序列, 请分别插入排序和选择排序,并比较哪一个更好 - * 只有"交换两个数字"和"比较两个数字"是一个操作. - * 更好的排序算法,意味着操作数更少. 输入中不会有 操作数相同 的情况. - *@输入 - * 第一行输入一个int32_t Τ(希腊字母 tau),代表测试用例数量 - * 之后每个测试用例 - * 第一行有size_t ν(希腊字母 Nu),代表数组长度 - * 接下来是ν个int32_t - *@输出 - * 对每个测试用例来讲 - * 第一行输出排序好的数组(注:最后一个数字后没有空格) - * 第二行 match (winner) { - * "insertion" => {"Insertion Sort wins!"} - * "selection" => {"Selection Sort wins!"} - * } - *@注: 不给样例解析的屑题目 - * */ + #include #include @@ -39,7 +21,7 @@ #ifdef ALGORITHM_TEST_MACRO namespace lab_03_C{ #endif -// TODO + using std::cin; using std::tie; using std::cout; @@ -93,43 +75,43 @@ inline input_type read() { } int32_t selection_sort(vector nums) { - int32_t will_return{0}; - const auto nums_size = static_cast(nums.size()); - for (int i = 0; i < nums_size - 1; ++i) { - //will_return++; + int32_t ops = 0; + const int n = static_cast(nums.size()); + for (int i = 0; i + 1 < n; ++i) { int k = i; - for (int j = i + 1; j < nums_size; ++j) { - //will_return++; - will_return++; - if (nums[k] > nums[j]) { - k = j; - } + for (int j = i + 1; j < n; ++j) { + // compare nums[k] and nums[j] + ++ops; + if (nums[j] < nums[k]) k = j; + } + if (k != i) { + // one swap operation + ++ops; + std::swap(nums[i], nums[k]); } - will_return++; - will_return++; - std::swap(nums[i], nums[k]); } - will_return++; - return will_return; + return ops; } int32_t insert_sort(vector nums) { - int32_t will_return{0}; - const auto nums_size = static_cast(nums.size()); - for (int i = 0; i < nums_size; i++) { - //will_return++; - for (int j = i; j >= 1; j--) { - //will_return++; - will_return++; + int32_t ops = 0; + const int n = static_cast(nums.size()); + for (int i = 1; i < n; ++i) { + int j = i; + while (j > 0) { + // compare nums[j-1] and nums[j] + ++ops; if (nums[j - 1] > nums[j]) { - will_return++; + // swap + ++ops; std::swap(nums[j - 1], nums[j]); + --j; + } else { + break; } } - will_return++; } - will_return++; - return will_return; + return ops; } output_type cal(const input_type &data) { diff --git a/algorithm/2021F/lab_03/lab_03_C/lab_03_C_test.cpp b/algorithm/2021F/lab_03/lab_03_C/test.cpp similarity index 98% rename from algorithm/2021F/lab_03/lab_03_C/lab_03_C_test.cpp rename to algorithm/2021F/lab_03/lab_03_C/test.cpp index 0771abb8..6c17c4a1 100644 --- a/algorithm/2021F/lab_03/lab_03_C/lab_03_C_test.cpp +++ b/algorithm/2021F/lab_03/lab_03_C/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_03_C.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_03/lab_03_C/resource/"; } diff --git a/algorithm/2021F/lab_03/lab_03_D/CMakeLists.txt b/algorithm/2021F/lab_03/lab_03_D/CMakeLists.txt index dce330ce..564aeae5 100644 --- a/algorithm/2021F/lab_03/lab_03_D/CMakeLists.txt +++ b/algorithm/2021F/lab_03/lab_03_D/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_03/lab_03_D/README.md b/algorithm/2021F/lab_03/lab_03_D/README.md new file mode 100644 index 00000000..6bb348eb --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_D/README.md @@ -0,0 +1,58 @@ +--- +SPDX-License-Identifier: CC-BY-NC-SA-4.0 +--- + +# lab_03_D + +## Description + +Given a sequence $\{a\}$ of $n$ distinct numbers, where $n$ is even. + +Permute the sequence to form a circle such that no element equals the average of its two neighbors. + +Formally, find a permutation $\{b\}$ of $\{a\}$ satisfying: + +- For all $i \in \{2,3,\dots,n-1\}$: $b_i \ne (b_{i-1}+b_{i+1})/2$. +- Also $b_1 \ne (b_2 + b_n)/2$ +- $b_n \ne (b_{n-1} + b_1)/2$. + +There may be multiple valid answers. Print any one. + +A solution is guaranteed to exist for every test case. + +## Input + +The first line contains an integer $n$. The second line contains $n$ integers $a_1, a_2, \dots, a_n$. + +Constraints: $n$ is even and $3 \le n \le 10^6$, $0 \le a_i \le 10^9$. + +## Output + +Print one line with $n$ integers: $b_1, b_2, \dots, b_n$. + +## Analysis + +算法先对数组进行排序,然后将前半部分和后半部分交替放置以构造圆排列。 + +每个较小的元素都会与较大的元素相邻,因此其值不可能等于两邻居的平均值;对较大元素亦然。 + +由于元素互不相同且 n 为偶数,两个半部分不会重叠,交错放置得到的序列是原序列的一个合法置换。 + +排序步骤时间复杂度为 $O(n\log n)$,交错拼接为线性时间,额外空间仅为输出数组(或常数工作空间)。 + +## Sample + +### Sample Input + +```text +6 +3 2 1 4 5 6 +``` + +### Sample Output + +```text +1 2 4 3 5 6 +``` + +> 似乎样例有错? 应该是 `1 4 2 5 3 6` diff --git a/algorithm/2021F/lab_02/lab_02_E/lab_02_E.cpp b/algorithm/2021F/lab_03/lab_03_D/main.cpp similarity index 63% rename from algorithm/2021F/lab_02/lab_02_E/lab_02_E.cpp rename to algorithm/2021F/lab_03/lab_03_D/main.cpp index a1939137..6900c564 100644 --- a/algorithm/2021F/lab_02/lab_02_E/lab_02_E.cpp +++ b/algorithm/2021F/lab_03/lab_03_D/main.cpp @@ -1,6 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: 2020-2025 nanoseeds -//@Tag TODO #include #include #include @@ -17,7 +16,7 @@ #include #ifdef ALGORITHM_TEST_MACRO -namespace lab_02_E{ +namespace lab_03_D{ #endif using std::cin; @@ -37,9 +36,9 @@ using std::unordered_set; using std::priority_queue; static constexpr const char end{'\n'}; -using num_t = int32_t; -using input_type = tuple, vector, vector>>; -using output_type = vector; +using num_t = int64_t; +using input_type = std::vector; +using output_type = std::vector; inline input_type read(); @@ -55,36 +54,41 @@ int main() { } inline input_type read() { - num_t n{0}, T{0}; - std::cin >> n >> T; - vector A(n, -1), B(n, -1); - for (int32_t i{0}; i < n; i++) { - std::cin >> A[i]; + int32_t n; + if (!(std::cin >> n)) return {}; + input_type a; + a.reserve(n); + for (int32_t i = 0; i < n; ++i) { + num_t v; + std::cin >> v; + a.push_back(v); } - for (int32_t i{0}; i < n; i++) { - std::cin >> B[i]; - } - num_t tempa, tempb; - vector> pairs; - for (int32_t i{0}; i < T; ++i) { - std::cin >> tempa >> tempb; - pairs.emplace_back(tempa, tempb); - } - return std::make_tuple(A, B, pairs); + return a; } output_type cal(const input_type &data) { - vector A, B; - vector> pairs; - tie(A, B, pairs) = data; - // TODO - return {6, 4}; + const int n = static_cast(data.size()); + if (n == 0) return {}; + // copy and sort + auto s = data; + std::sort(s.begin(), s.end()); + output_type b(n); + const int half = n / 2; + // Interleave: small, large, small2, large2, ... + for (int i = 0; i < half; ++i) { + b[2 * i] = s[i]; + b[2 * i + 1] = s[i + half]; + } + return b; } void output(const output_type &data) { - for (auto &&dat: data) { - cout << dat << end; + const int n = static_cast(data.size()); + for (int i = 0; i < n; ++i) { + if (i) std::cout << ' '; + std::cout << data[i]; } + std::cout << end; } static const auto faster_streams = [] { diff --git a/algorithm/2021F/lab_03/lab_03_D/resource/01.data.in b/algorithm/2021F/lab_03/lab_03_D/resource/01.data.in new file mode 100644 index 00000000..d2cac55f --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_D/resource/01.data.in @@ -0,0 +1,2 @@ +6 +3 2 1 4 5 6 diff --git a/algorithm/2021F/lab_03/lab_03_D/resource/01.data.out b/algorithm/2021F/lab_03/lab_03_D/resource/01.data.out new file mode 100644 index 00000000..35eb7db0 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_D/resource/01.data.out @@ -0,0 +1 @@ +1 4 2 5 3 6 diff --git a/algorithm/2021F/lab_03/lab_03_D/test.cpp b/algorithm/2021F/lab_03/lab_03_D/test.cpp new file mode 100644 index 00000000..7f2cbc69 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_D/test.cpp @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_03/lab_03_D/resource/"; } + + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_03_D { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence", "[test 03 D]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_03/lab_03_E/CMakeLists.txt b/algorithm/2021F/lab_03/lab_03_E/CMakeLists.txt index c43d3c98..f6252ecc 100644 --- a/algorithm/2021F/lab_03/lab_03_E/CMakeLists.txt +++ b/algorithm/2021F/lab_03/lab_03_E/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_03/lab_03_E/README.md b/algorithm/2021F/lab_03/lab_03_E/README.md new file mode 100644 index 00000000..906a1ca0 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_E/README.md @@ -0,0 +1,53 @@ +--- +SPDX-License-Identifier: CC-BY-NC-SA-4.0 +--- + +# lab_03_E + +## Description + +You are given a random sequence $\{a\}$ of $n$ distinct elements. + +You can swap adjacent elements, and the cost of swapping $(a_i,a_{i+1})$ equals $\min(a_i,a_{i+1})$. + +Compute the minimum total cost to sort the sequence in ascending order by performing adjacent swaps. + +## Input + +The first line contains an integer $n$. + +The second line contains $n$ integers $a_1,a_2,\dots,a_n$. + +Constraints: $1 \le n \le 10^5$, $0 \le a_i \le 10^9$. + +## Output + +Output a single integer: the minimum total cost required to sort the sequence. + +## Sample + +### Sample Input + +```text +5 +1 3 2 4 5 +``` + +### Sample Output + +```text +2 +``` + +## 复用信息 + ++ Contest 1095:CS203 2021 Fall Lab 03 Sorting ++ Contest 1096:CS217 2021 Fall Lab 03 Sorting ++ Contest 1163:CS203 2024 Fall Lab 2 + +## Algorithm Analysis (实现说明) + ++ 思路: 题目要求通过相邻交换把数组排序, 交换 (a_i, a_{i+1}) 的代价为 min(a_i, a_{i+1})。将数组排序所需的代价等于对每次把较大的元素向右移动时累加被它跨越的较小元素的值。一个等价的视角是: 对于当前元素 x,考虑其左侧比 x 大的元素的个数 cnt,大元素每次与 x 交换时的最小值贡献为 x,因此该元素对答案的贡献为 x * cnt。 ++ 实现要点: 先做坐标压缩得到秩 rank;使用 Fenwick 树维护已遍历元素的计数。遍历原数组,从左到右查询当前值右侧的已出现更大的元素数 greater = i - leq(其中 leq 是 <= 当前值 的计数),把 a[i] * greater 累加到答案,再把当前值加入 Fenwick 树。 ++ 复杂度: 坐标压缩 O(n log n),遍历与 Fenwick 操作 O(n log n)。总体 O(n log n),空间 O(n)。 ++ 边界情况: n<=1 时直接返回 0;重复元素的处理通过压缩与 <= 计数保证正确性。 diff --git a/algorithm/2021F/lab_03/lab_03_E/lab_03_E.cpp b/algorithm/2021F/lab_03/lab_03_E/lab_03_E.cpp deleted file mode 100644 index 75c4a0a6..00000000 --- a/algorithm/2021F/lab_03/lab_03_E/lab_03_E.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later -// SPDX-FileCopyrightText: 2020-2025 nanoseeds -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef ALGORITHM_TEST_MACRO -namespace lab_03_E{ -#endif - -using std::cin; -using std::tie; -using std::cout; -using std::list; -using std::sort; -using std::array; -using std::deque; -using std::queue; -using std::stack; -using std::tuple; -using std::string; -using std::vector; -using std::unordered_map; -using std::unordered_set; -using std::priority_queue; -static constexpr const char end{'\n'}; - -using num_t = int32_t; -using input_type = tuple; -using output_type = num_t; - -inline input_type read(); - -output_type cal(input_type data); - -void output(const output_type &data); - -int main() { - auto input_data = read(); - auto output_data = cal(input_data); - output(output_data); - return 0; -} - -inline input_type read() { - num_t a{0}, b{0}; - std::cin >> a >> b; - return std::make_tuple(a, b); -} - -output_type cal(input_type data) { - num_t a{0}, b{0}; - tie(a, b) = data; - num_t c = a + b; - return c; -} - -void output(const output_type &data) { - cout << data << end; -} - -static const auto faster_streams = [] { - srand(time(nullptr)); - // use time to init the random seed - std::ios::sync_with_stdio(false); - std::istream::sync_with_stdio(false); - std::ostream::sync_with_stdio(false); - std::cin.tie(nullptr); - std::cout.tie(nullptr); - // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. - return 0; -}(); -#ifdef ALGORITHM_TEST_MACRO -} -#endif diff --git a/algorithm/2021F/lab_03/lab_03_E/lab_03_E_test.cpp b/algorithm/2021F/lab_03/lab_03_E/lab_03_E_test.cpp deleted file mode 100644 index 2ed5a30f..00000000 --- a/algorithm/2021F/lab_03/lab_03_E/lab_03_E_test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later -// SPDX-FileCopyrightText: 2020-2025 nanoseeds -#ifdef ALGORITHM_TEST_MACRO - -#include -#include -#include -#include -#include - -#include "lab_03_E.cpp" - -std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_03/lab_03_E/resource/"; } - - -const std::string CS203_redirect::file_paths = getFilePath(); - -namespace lab_03_E { - -using std::tie; -using std::cin; -using std::cout; -using std::tuple; -using std::vector; - -using Catch::Matchers::Equals; -using Catch::Matchers::UnorderedEquals; -using Catch::Matchers::Contains; - -TEST_CASE("test case 1", "[test 03 E]") { - const auto output_data = cal(std::make_tuple(114, 514)); - CHECK(output_data == 628); - CHECK(1 + 2 == 3); - vector vec{2, 7, 11, 15}; - SECTION("CHECK_THAT 1") { - CHECK_THAT(vec, Contains({2})); - }SECTION("vec matcher") { - CHECK_THAT(vec, UnorderedEquals({15, 11, 7, 2})); - } -} -// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` -TEST_CASE("test case with sequence", "[test 03 E][.]") { - CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] - sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in - sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out - sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out - const auto files_name = sequence.get_files(true); - // 获取一个std::tuple , - // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. - for (const auto &file_name: files_name) { - string datain, dataout, testout; // 声明 - tie(datain, dataout, testout) = file_name; // 解包 - { - const CS203_redirect cr{datain, testout}; // 重定向输入,输出 - main(); - // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 - } - CHECK(compareFiles(testout, dataout)); - } -} -} -#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_03/lab_03_E/main.cpp b/algorithm/2021F/lab_03/lab_03_E/main.cpp new file mode 100644 index 00000000..881b9167 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_E/main.cpp @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_03_E{ +#endif + +using std::cin; +using std::tie; +using std::cout; +using std::list; +using std::sort; +using std::array; +using std::deque; +using std::queue; +using std::stack; +using std::tuple; +using std::string; +using std::vector; +using std::unordered_map; +using std::unordered_set; +using std::priority_queue; +static constexpr const char end{'\n'}; + +using i32 = int32_t; +using i64 = int64_t; + +using input_type = std::pair>; +using output_type = i64; + +inline input_type read_input(); + +output_type cal(const input_type &data); + +void output(const output_type &data); + +int main() { + const auto input_data = read_input(); + const auto output_data = cal(input_data); + output(output_data); + return 0; +} + +inline input_type read_input() { + i32 n{0}; + std::cin >> n; + vector a; + a.resize(n); + for (i32 i = 0; i < n; ++i) std::cin >> a[i]; + return {n, a}; +} + +// Fenwick tree for counts +struct Fenwick { + int n; + vector bit; + Fenwick(int _n = 0) { init(_n); } + void init(int _n) { n = _n; bit.assign(n+1, 0); } + void add(int idx, i32 val) { + for (; idx <= n; idx += idx & -idx) bit[idx] += val; + } + i32 sumPrefix(int idx) const { + i32 r = 0; + for (; idx > 0; idx -= idx & -idx) r += bit[idx]; + return r; + } +}; + +output_type cal(const input_type &data) { + const i32 n = data.first; + const auto &a = data.second; + if (n <= 1) return 0; + // coordinate compression + vector vals = a; + std::sort(vals.begin(), vals.end()); + vals.erase(std::unique(vals.begin(), vals.end()), vals.end()); + Fenwick fw(static_cast(vals.size())); + i64 ans = 0; + for (i32 i = 0; i < n; ++i) { + int rk = static_cast(std::lower_bound(vals.begin(), vals.end(), a[i]) - vals.begin()) + 1; // 1-based + i32 leq = fw.sumPrefix(rk); // number of previous <= a[i] + i32 prev = i; // number of previous elements + i32 greater = prev - leq; // previous elements > a[i] + ans += a[i] * static_cast(greater); + fw.add(rk, 1); + } + return ans; +} + +void output(const output_type &data) { + cout << data << end; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_03/lab_03_E/resource/01.data.in b/algorithm/2021F/lab_03/lab_03_E/resource/01.data.in new file mode 100644 index 00000000..a0aa4402 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_E/resource/01.data.in @@ -0,0 +1,2 @@ +5 +1 3 2 4 5 diff --git a/algorithm/2021F/lab_03/lab_03_E/resource/01.data.out b/algorithm/2021F/lab_03/lab_03_E/resource/01.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_E/resource/01.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_03/lab_03_E/test.cpp b/algorithm/2021F/lab_03/lab_03_E/test.cpp new file mode 100644 index 00000000..3c831882 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_E/test.cpp @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_03/lab_03_E/resource/"; } + + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_03_E { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence", "[test 03 E]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_03/lab_03_F/CMakeLists.txt b/algorithm/2021F/lab_03/lab_03_F/CMakeLists.txt index 7bd14a82..3bd8bb2b 100644 --- a/algorithm/2021F/lab_03/lab_03_F/CMakeLists.txt +++ b/algorithm/2021F/lab_03/lab_03_F/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_03/lab_03_F/README.md b/algorithm/2021F/lab_03/lab_03_F/README.md new file mode 100644 index 00000000..2bcee0e8 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_F/README.md @@ -0,0 +1,65 @@ +--- +SPDX-License-Identifier: CC-BY-NC-SA-4.0 +--- + +# lab_03_F + +## Description + +You have $n$ plants. + +The $i$-th plant has height $h_i$ and strength $s_i$. + +There are two fertilizers: $F_h$ and $F_s$. + +Applying one $F_h$ to a plant doubles its height. + +Applying one $F_s$ sets the plant's strength equal to its height. + +You may use at most $p$ bags of $F_h$ and at most $q$ bags of $F_s$. + +Maximize the sum of strengths $\sum s_i$ after applying at most $p$ of $F_h$ and at most $q$ of $F_s$. + +## Input + +The first line contains three integers $n, p, q$. + +Then follow $n$ lines. + +Each of the next $n$ lines contains two integers $h_i, s_i$. + +Constraints: $1 \le n \le 2\cdot 10^5$, $0 \le p \le 20$, $0 \le q \le 2\cdot 10^5$, $1 \le h_i, s_i \le 10^9$. + +## Output + +Print one integer: the maximum possible sum $\sum s_i$. + +## Sample + +### Sample Input + +```text +2 1 1 +10 8 +6 1 +``` + +### Sample Output + +```text +21 +``` + +## 复用信息 + ++ Contest 1095:CS203 2021 Fall Lab 03 Sorting ++ Contest 1096:CS217 2021 Fall Lab 03 Sorting ++ Contest 1137:CS203 2023 Fall Lab 2 Sorting ++ Contest 1187:CS203 2025 Fall Lab 2 Sorting + +## Algorithm Analysis (实现说明) + ++ 思路: 将两种操作(对高度使用 F_h 翻倍, 使用 F_s 将强度设为高度)组合来最大化总强度。先把每个植物不使用额外肥料时的基线强度 base = sum s_i 记下。对每个植物,定义 g0 = max(h_i - s_i, 0) 表示使用 F_s 可带来的净增量。使用最多 q 个 F_s 时,优先把 q 个 g0 最大的植物设为 s= h。 ++ 对于最多 p 次将某一植物的高度翻倍的操作(p<=20),可以枚举把所有 p 放在某一植物上的情况: 计算该植物翻倍后的 g1 = max(h_i * 2^p - s_i, 0),并把 g0 的排序中替换原位置后计算前 q 个的和得到候选值。取所有枚举中的最大值。为高效实现, 先对 g0 做降序排序并构建前缀和; 枚举时用二分/插入位置快速计算替换后前 q 个之和。 ++ 复杂度: 排序 O(n log n);枚举 n 个位置并在 O(log n) 或 O(1) 时间内计算新前缀和,总体 O(n log n)。空间 O(n)。 ++ 边界情况: p=0 时相当于只使用 F_s;q=0 时只考虑翻倍的增益;当 q>n 时取 n 个最大增益。 diff --git a/algorithm/2021F/lab_03/lab_03_F/lab_03_F_test.cpp b/algorithm/2021F/lab_03/lab_03_F/lab_03_F_test.cpp deleted file mode 100644 index eed57d8f..00000000 --- a/algorithm/2021F/lab_03/lab_03_F/lab_03_F_test.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later -// SPDX-FileCopyrightText: 2020-2025 nanoseeds -#ifdef ALGORITHM_TEST_MACRO - -#include -#include -#include -#include -#include - -#include "lab_03_F.cpp" - -std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_03/lab_03_F/resource/"; } - - -const std::string CS203_redirect::file_paths = getFilePath(); - -namespace lab_03_F { - -using std::tie; -using std::cin; -using std::cout; -using std::tuple; -using std::vector; - -using Catch::Matchers::Equals; -using Catch::Matchers::UnorderedEquals; -using Catch::Matchers::Contains; - -TEST_CASE("test case 1", "[test 03 F]") { - const auto output_data = cal(std::make_tuple(114, 514)); - CHECK(output_data == 628); - CHECK(1 + 2 == 3); - vector vec{2, 7, 11, 15}; - SECTION("CHECK_THAT 1") { - CHECK_THAT(vec, Contains({2})); - }SECTION("vec matcher") { - CHECK_THAT(vec, UnorderedEquals({15, 11, 7, 2})); - } -} -// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` -TEST_CASE("test case with sequence", "[test 03 F][.]") { - CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] - sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in - sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out - sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out - const auto files_name = sequence.get_files(true); - // 获取一个std::tuple , - // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. - for (const auto &file_name: files_name) { - string datain, dataout, testout; // 声明 - tie(datain, dataout, testout) = file_name; // 解包 - { - const CS203_redirect cr{datain, testout}; // 重定向输入,输出 - main(); - // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 - } - CHECK(compareFiles(testout, dataout)); - } -} -} -#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_03/lab_03_F/main.cpp b/algorithm/2021F/lab_03/lab_03_F/main.cpp new file mode 100644 index 00000000..c5752bd5 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_F/main.cpp @@ -0,0 +1,170 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_03_F{ +#endif + +using std::cin; +using std::tie; +using std::cout; +using std::pair; +using std::list; +using std::sort; +using std::array; +using std::deque; +using std::queue; +using std::stack; +using std::tuple; +using std::string; +using std::vector; +using std::unordered_map; +using std::unordered_set; +using std::priority_queue; +static constexpr const char end{'\n'}; + +using i32 = int32_t; +using i64 = int64_t; + +using input_type = tuple, vector>; // n,p,q,h[],s[] +using output_type = i64; + +inline input_type read_input(); + +output_type cal(const input_type &data); + +void output(const output_type &data); + +int main() { + const auto input_data = read_input(); + const auto output_data = cal(input_data); + output(output_data); + return 0; +} + +inline input_type read_input() { + i32 n; i32 p; i32 q; + std::cin >> n >> p >> q; + vector h(n), s(n); + for (i32 i = 0; i < n; ++i) std::cin >> h[i] >> s[i]; + return std::make_tuple(n, p, q, h, s); +} + +output_type cal(const input_type &data) { + i32 n, p, q; + vector h, s; + tie(n, p, q, h, s) = data; + i64 base = 0; + vector g0(n); + for (i32 i = 0; i < n; ++i) { + base += s[i]; + g0[i] = std::max(h[i] - s[i], 0); + } + i32 cnt = std::min(q, n); + // sort g0 descending with indices + vector> vec; + vec.reserve(n); + for (int i = 0; i < n; ++i) vec.emplace_back(g0[i], i); + sort(vec.begin(), vec.end(), [](const pair&a, const pair&b){ + if (a.first != b.first) return a.first > b.first; + return a.second < b.second; + }); + vector gs(n); + vector pos(n); + for (int i = 0; i < n; ++i) { + gs[i] = vec[i].first; + pos[ vec[i].second ] = i; + } + vector pref(n+1, 0); + for (int i = 0; i < n; ++i) pref[i+1] = pref[i] + gs[i]; + + i64 best = base + pref[cnt]; + + // Precompute multiplier 2^p + i64 mul = 1; + for (int i = 0; i < p; ++i) mul <<= 1; + + for (int idx = 0; idx < n; ++idx) { + // value if we apply all p F_h to idx + i64 hi = h[idx] * mul; + i64 g1 = std::max(hi - s[idx], 0); + // compute insertion position in gs (descending) + auto it = std::lower_bound(gs.begin(), gs.end(), g1, std::greater()); + int pos_insert = static_cast(it - gs.begin()); + int orig_pos = pos[idx]; + int pos_excl = (pos_insert <= orig_pos) ? pos_insert : pos_insert - 1; + + // sum_top_excl: sum of top cnt values after removing original g0[idx] + i64 sum_top_excl = 0; + if (cnt == 0) { + sum_top_excl = 0; + } else if (orig_pos >= cnt) { + sum_top_excl = pref[cnt]; + } else { + // orig_pos < cnt + sum_top_excl = pref[cnt] - gs[orig_pos]; + if (cnt < n) sum_top_excl += gs[cnt]; + } + + i64 total_gain_top = 0; + if (pos_excl >= cnt) { + total_gain_top = sum_top_excl; + } else { + // g1 enters top cnt, drop element at index cnt-1 of multiset_excl + i64 drop = 0; + if (cnt == 0) drop = 0; + else if (orig_pos >= cnt) { + drop = gs[cnt-1]; + } else { + // orig_pos < cnt + if (cnt < n) drop = gs[cnt]; else drop = 0; + } + total_gain_top = sum_top_excl + g1 - drop; + } + + i64 candidate = base + total_gain_top; + if (candidate > best) best = candidate; + } + + return best; +} + +void output(const output_type &data) { + cout << data << end; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_03/lab_03_F/resource/01.data.in b/algorithm/2021F/lab_03/lab_03_F/resource/01.data.in new file mode 100644 index 00000000..8b31598c --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_F/resource/01.data.in @@ -0,0 +1,3 @@ +2 1 1 +10 8 +6 1 diff --git a/algorithm/2021F/lab_03/lab_03_F/resource/01.data.out b/algorithm/2021F/lab_03/lab_03_F/resource/01.data.out new file mode 100644 index 00000000..aabe6ec3 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_F/resource/01.data.out @@ -0,0 +1 @@ +21 diff --git a/algorithm/2021F/lab_03/lab_03_F/test.cpp b/algorithm/2021F/lab_03/lab_03_F/test.cpp new file mode 100644 index 00000000..716d221a --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_F/test.cpp @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_03/lab_03_F/resource/"; } + + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_03_F { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence", "[test 03 F]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_03/lab_03_G/CMakeLists.txt b/algorithm/2021F/lab_03/lab_03_G/CMakeLists.txt new file mode 100644 index 00000000..768dc1e2 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_G/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER G) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_03/lab_03_G/README.md b/algorithm/2021F/lab_03/lab_03_G/README.md new file mode 100644 index 00000000..4e4a561c --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_G/README.md @@ -0,0 +1,58 @@ +--- +SPDX-License-Identifier: CC-BY-NC-SA-4.0 +--- + +# lab_03_G + +## Description + +There are too many cables under your table, and you want to tidy them. + +You designed a simple cabling scheme: There are n cables, each cable is a line in form of $y=k_i∗x+b_i$, your table is the region between $x=x1$ and $x=x2$ + +If any two cables intersect on your table region (not include the edges), your table is not tidy and you need to design another scheme. + +More formally, there are n lines in form of $y=k_i∗x+b_i$, if there are two lines intersect on $(x_p,y_p)$, and $x1 #ifdef ALGORITHM_TEST_MACRO -namespace lab_03_F{ +namespace lab_03_G{ #endif using std::cin; @@ -37,8 +37,17 @@ using std::priority_queue; static constexpr const char end{'\n'}; using num_t = int32_t; -using input_type = tuple; -using output_type = num_t; +using i64 = int64_t; + +struct Input { + int32_t n; + i64 x1; + i64 x2; + vector > lines; // (k, b) +}; + +using input_type = Input; +using output_type = string; inline input_type read(); @@ -54,16 +63,52 @@ int main() { } inline input_type read() { - num_t a{0}, b{0}; - std::cin >> a >> b; - return std::make_tuple(a, b); + Input in; + int32_t n; + i64 x1, x2; + cin >> n >> x1 >> x2; + in.n = n; + in.x1 = x1; + in.x2 = x2; + in.lines.reserve(static_cast(n)); + for (int i = 0; i < n; ++i) { + i64 k, b; + cin >> k >> b; + in.lines.emplace_back(k, b); + } + return in; } output_type cal(input_type data) { - num_t a{0}, b{0}; - tie(a, b) = data; - num_t c = a + b; - return c; + const int n = data.n; + const i64 x1 = data.x1; + const i64 x2 = data.x2; + // compute values at x1 and x2 + vector > ys; + ys.reserve(static_cast(n)); + for (int i = 0; i < n; ++i) { + const i64 k = data.lines[i].first; + const i64 b = data.lines[i].second; + const i64 y1 = k * x1 + b; + const i64 y2 = k * x2 + b; + ys.emplace_back(y1, y2); + } + + // order indices by (y1, y2) to ensure ties at x1 are resolved by x2 + vector ord(n); + for (int i = 0; i < n; ++i) ord[i] = i; + sort(ord.begin(), ord.end(), [&](int a, int b) { + if (ys[a].first != ys[b].first) return ys[a].first < ys[b].first; + return ys[a].second < ys[b].second; + }); + + // check for inversion in y2 sequence + for (int i = 0; i + 1 < n; ++i) { + const i64 y2_cur = ys[ord[i]].second; + const i64 y2_nxt = ys[ord[i + 1]].second; + if (y2_cur > y2_nxt) return string("YES"); + } + return string("NO"); } void output(const output_type &data) { diff --git a/algorithm/2021F/lab_03/lab_03_G/resource/01.data.in b/algorithm/2021F/lab_03/lab_03_G/resource/01.data.in new file mode 100644 index 00000000..5b9cc938 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_G/resource/01.data.in @@ -0,0 +1,4 @@ +2 +1 3 +1 0 +-1 3 diff --git a/algorithm/2021F/lab_03/lab_03_G/resource/01.data.out b/algorithm/2021F/lab_03/lab_03_G/resource/01.data.out new file mode 100644 index 00000000..f033a501 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_G/resource/01.data.out @@ -0,0 +1 @@ +YES diff --git a/algorithm/2021F/lab_03/lab_03_G/test.cpp b/algorithm/2021F/lab_03/lab_03_G/test.cpp new file mode 100644 index 00000000..ea444cc9 --- /dev/null +++ b/algorithm/2021F/lab_03/lab_03_G/test.cpp @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_03/lab_03_G/resource/"; } + + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_03_G { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence", "[test 03 F]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_04/CMakeLists.txt b/algorithm/2021F/lab_04/CMakeLists.txt index ebb3bfc9..74cdbbc1 100644 --- a/algorithm/2021F/lab_04/CMakeLists.txt +++ b/algorithm/2021F/lab_04/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -set(dependencies A 2A B C D) # E F +set(dependencies A 2A B C D E F G) # E F foreach (elementName IN LISTS dependencies) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${elementName}) endforeach () diff --git a/algorithm/2021F/lab_04/README.md b/algorithm/2021F/lab_04/README.md new file mode 100644 index 00000000..bca1bbb1 --- /dev/null +++ b/algorithm/2021F/lab_04/README.md @@ -0,0 +1,33 @@ +# CS203 2021 Fall — Lab 04: LinkedList + +``` meta +cid=1098 +``` + +Welcome to CS203 2021 Fall Lab 04! This lab focuses on linked-list related problems. + +There are seven problems in this lab. Read samples and hints carefully — they often contain important details. + +Score: + +- A: 10 +- B: 15/10 +- C: 15/10 +- D: 20/15 +- E: 20/15 +- F: 20 +- G: undefined/20 + +## Problems + +| Problem | problem id | +|---:|---:| +| A | 1435 | +| B | 1436 | +| C | 1442 | +| D | 1439 | +| E | 1440 | +| F | 1438 | +| G | 1441 | + +A, D, E题被复用 diff --git a/algorithm/2021F/lab_04/cs203.submit.csv b/algorithm/2021F/lab_04/cs203.submit.csv new file mode 100644 index 00000000..74ce7906 --- /dev/null +++ b/algorithm/2021F/lab_04/cs203.submit.csv @@ -0,0 +1,8 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 277, 1, 360, 339, 1, 14, 187, 90, 1269, 22, 404, 843 +B, 247, 1, 239, 339, 7, 74, 108, 1015, 32, 148, 835 +C, 229, 197, 271, 29, 104, 117, 44, 991, 31, 111, 849 +D, 242, 1, 364, 500, 16, 50, 64, 62, 1299, 11, 239, 1049 +E, 166, 73, 381, 602, 13, 492, 369, 76, 2172, 42, 405, 1725 +F, 141, 1, 129, 400, 27, 13, 203, 37, 951, 3, 253, 695 +Total, 1302, 77, 1670, 2451, 86, 680, 1014, 417, 7697, 141, 1560, 5996 diff --git a/algorithm/2021F/lab_04/cs217.submit.csv b/algorithm/2021F/lab_04/cs217.submit.csv new file mode 100644 index 00000000..30ba0bd0 --- /dev/null +++ b/algorithm/2021F/lab_04/cs217.submit.csv @@ -0,0 +1,9 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 46, 58, 51, 14, 14, 183, 6, 115, 62 +B, 53, 1, 15, 20, 4, 8, 101, 6, 42, 53 +C, 44, 13, 18, 1, 6, 1, 2, 85, 14, 23, 48 +D, 55, 8, 42, 6, 22, 11, 144, 12, 67, 65 +E, 43, 38, 46, 4, 66, 21, 9, 227, 1, 83, 143 +F, 68, 22, 59, 11, 1, 16, 9, 186, 119, 67 +G, 65, 60, 32, 15, 7, 179, 3, 98, 78 +Total, 374, 1, 214, 268, 16, 79, 93, 60, 1105, 42, 547, 516 diff --git a/algorithm/2021F/lab_04/lab_04_2A/CMakeLists.txt b/algorithm/2021F/lab_04/lab_04_2A/CMakeLists.txt index a78119fe..da52f0d3 100644 --- a/algorithm/2021F/lab_04/lab_04_2A/CMakeLists.txt +++ b/algorithm/2021F/lab_04/lab_04_2A/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_04/lab_04_2A/lab_04_2A.cpp b/algorithm/2021F/lab_04/lab_04_2A/main.cpp similarity index 100% rename from algorithm/2021F/lab_04/lab_04_2A/lab_04_2A.cpp rename to algorithm/2021F/lab_04/lab_04_2A/main.cpp diff --git a/algorithm/2021F/lab_04/lab_04_2A/lab_04_2A_test.cpp b/algorithm/2021F/lab_04/lab_04_2A/test.cpp similarity index 98% rename from algorithm/2021F/lab_04/lab_04_2A/lab_04_2A_test.cpp rename to algorithm/2021F/lab_04/lab_04_2A/test.cpp index 70c6c80c..ced558de 100644 --- a/algorithm/2021F/lab_04/lab_04_2A/lab_04_2A_test.cpp +++ b/algorithm/2021F/lab_04/lab_04_2A/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_04_2A.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_04/lab_04_A/resource/"; } diff --git a/algorithm/2021F/lab_04/lab_04_A/CMakeLists.txt b/algorithm/2021F/lab_04/lab_04_A/CMakeLists.txt index 354751e1..40897f09 100644 --- a/algorithm/2021F/lab_04/lab_04_A/CMakeLists.txt +++ b/algorithm/2021F/lab_04/lab_04_A/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_04/lab_04_A/README.md b/algorithm/2021F/lab_04/lab_04_A/README.md new file mode 100644 index 00000000..862d5f3d --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_A/README.md @@ -0,0 +1,88 @@ +# lab_04_A — Polynomial Sum + +## Description + +Given two polynomials with n and m terms, please calculate the sum of the two polynomials. + +Inputs and outputs are exponentially larger to smaller + +### Input + +The first line has two numbers: n and m $(0` 是一个理想的选择. 在这个映射中: + ++ 键 (Key): 存储多项式的 指数 (exponent). ++ 值 (Value): 存储对应项的 系数 (coefficient). + +`std::map` 的主要优势在于它是一个基于红黑树的有序关联容器, 它会根据键(在此即指数)自动进行升序排序. 这极大地简化了后续按指数顺序输出的需求. + +### 算法流程 + +1. 初始化: 创建一个 `std::map` 实例, 用于存放最终合并后的多项式. + +2. 读取多项式: + + 遍历第一个多项式的所有项. 对于每一个读入的 "系数-指数" 对, 将其存入 map 中. `map[指数] = 系数`. + + 遍历第二个多项式的所有项. 对于每一个读入的 "系数-指数" 对, 将其系数累加到 map 中对应指数的项上. `map[指数] += 系数`. `std::map` 的 `[]` 操作符在这里非常方便: 如果 map 中已存在该指数, 它会直接访问并允许修改对应的系数值; 如果不存在, 它会自动创建一个新条目, 并将系数初始化为0, 然后再执行加法. + +3. 处理零系数项: 在合并过程中, 某些项的系数可能变为零. `std::map` 中会保留这些条目. 虽然本题的实现没有显式移除它们, 但在输出时可以根据需要进行过滤. + +4. 输出结果: + + 首先, 输出 map 的大小 `map.size()`, 这代表了结果多项式的项数. + + 由于 `std::map` 按键(指数)升序存储, 而题目要求按指数降序输出, 因此需要使用反向迭代器 (`crbegin()` 到 `crend()`) 来遍历 map. + + 在遍历过程中, 打印每个项的系数和指数. 代码中包含一个 `if (iter->first != 0)` 的判断, 这意味着指数为0的项(即常数项)不会被输出. 根据题目要求和样例, 这可能是特定题设下的特殊规则. + +这种方法利用了 `std::map` 的特性, 以简洁高效的方式完成了多项式的合并与排序, 完全符合 `AGENTS.md` 中提倡的利用标准库算法和数据结构的原则. diff --git a/algorithm/2021F/lab_04/lab_04_A/lab_04_A.cpp b/algorithm/2021F/lab_04/lab_04_A/main.cpp similarity index 78% rename from algorithm/2021F/lab_04/lab_04_A/lab_04_A.cpp rename to algorithm/2021F/lab_04/lab_04_A/main.cpp index 1202c376..1e1dcd4b 100644 --- a/algorithm/2021F/lab_04/lab_04_A/lab_04_A.cpp +++ b/algorithm/2021F/lab_04/lab_04_A/main.cpp @@ -1,31 +1,17 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: 2020-2025 nanoseeds -/* - *@题目描述 - * 给出两个各有ν(希腊字母Nu),μ(希腊字母Mu)长的多项式Ν(大写希腊字母Nu),Μ(大写希腊字母Mu),请计算两者之和 - *@输入 - * 第一行输入两个int32_t,(0,10^6) - * 之后ν行输入,分别是Ν的 ${系数},${指数} - * 之后μ行输入,分别是Μ的 ${系数},${指数} - * 所有系数指数都在(-10^9,10^9) - * PS: 输入全为int32_t - *@输出 - * 第一行int32_t, 输出项数 - * 之后分行输出 ${系数},${指数} - * */ // DONE -#ifndef ALGORITHM_TEST_MACRO -#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") -#pragma GCC optimize("inline-small-functions") -#pragma GCC optimize("-finline-small-functions") -#pragma GCC target("mmx") -#endif #include #include #include -#ifdef ALGORITHM_TEST_MACRO +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else namespace lab_04_A{ #endif diff --git a/algorithm/2021F/lab_04/lab_04_A/lab_04_A_test.cpp b/algorithm/2021F/lab_04/lab_04_A/test.cpp similarity index 98% rename from algorithm/2021F/lab_04/lab_04_A/lab_04_A_test.cpp rename to algorithm/2021F/lab_04/lab_04_A/test.cpp index ff0ed881..63cebeec 100644 --- a/algorithm/2021F/lab_04/lab_04_A/lab_04_A_test.cpp +++ b/algorithm/2021F/lab_04/lab_04_A/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_04_A.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_04/lab_04_A/resource/"; } diff --git a/algorithm/2021F/lab_04/lab_04_B/CMakeLists.txt b/algorithm/2021F/lab_04/lab_04_B/CMakeLists.txt index c490830a..dac0839a 100644 --- a/algorithm/2021F/lab_04/lab_04_B/CMakeLists.txt +++ b/algorithm/2021F/lab_04/lab_04_B/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_04/lab_04_B/README.md b/algorithm/2021F/lab_04/lab_04_B/README.md new file mode 100644 index 00000000..d31e74f9 --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_B/README.md @@ -0,0 +1,121 @@ +--- +SPDX-License-Identifier: CC-BY-NC-SA-4.0 +--- + +# lab_04_B + +## Description + +Given a group of n students arranged in a line under the edict that while the line has students, repeatedly execute the i-th student for i = 1..len stepping by m (i.e. every m-th student is removed). Produce the going-out order of students (a standard Josephus elimination order). + +## Input + +Two numbers n, m (1 < m <= 10, m <= n < 2e6) + +## Output + +The going-out order of students (space separated indices). + +## Sample + +### Sample Input + +```text +5 2 +``` + +### Sample Output + +```text +1 3 5 2 4 +``` + +## Notes + +This is a classic Josephus problem. For large n you should use a linked-list/simulation with efficient removal or use a data structure like an order-statistics tree to get O(n log n) or better. + +## cn-翻译 + +甲 个学生排成一排 +按下列算法踢人 +一直 开 行列有人 小 + 赋 行列之长 于 冷 + 赋 一 于 爱 + 一直 开 爱 不大于 冷 毕 + 踢出 队列 之 爱 + 爱 自增 MU + +## 样例 + +输入:`5 2` +输出:`1 3 5 2 4` + +### 分析: + +``` +NU=5,MU=2 +1 <= 2 <= 10 +2 <= 5 <= 2000000 +``` + +首先排列 `1 2 3 4 5` +第一轮踢掉`1,3,5` 留下`2,4` +第二轮踢掉`2` 留下`4` +第三轮踢掉`4` + +## 解题思路 + +### 问题分析 + +本题是经典的 约瑟夫问题 (Josephus Problem) 的变种. `n` 个学生排成一队, 从第 1 个学生开始, 每隔 `m` 个位置就淘汰一人, 直到所有人都被淘汰. 要求输出学生被淘汰的顺序. + +与传统的环形约瑟夫问题不同, 这里的学生是 线性排列 的. 每次淘汰操作会使队列的长度动态缩短, 并且计数始终从当前队列的头部重新开始. + +例如, 初始队列为 `[1, 2, 3, 4, 5]`, `m = 2`. + +1. 第一轮淘汰: + + 淘汰第 1 个: `[2, 3, 4, 5]`, 淘汰顺序: `[1]` + + 淘汰第 1 + 2 = 3 个 (在原队列中的位置): `[2, 4, 5]`, 淘汰顺序: `[1, 3]` + + 淘汰第 1 + 2 + 2 = 5 个 (在原队列中的位置): `[2, 4]`, 淘汰顺序: `[1, 3, 5]` +2. 第二轮淘汰 (队列重置为 `[2, 4]`): + + 淘汰第 1 个: `[4]`, 淘汰顺序: `[1, 3, 5, 2]` +3. 第三轮淘汰 (队列重置为 `[4]`): + + 淘汰第 1 个: `[]`, 淘汰顺序: `[1, 3, 5, 2, 4]` + +### 数据结构与算法 + +为了模拟这个过程, 我们需要一个能够高效执行 "按位置删除" 操作的数据结构. + +#### 1. `std::vector` (朴素方法) + +最直观的方法是使用 `std::vector` 来存储学生队列. 每次淘汰一个学生, 就从 `vector` 中删除对应位置的元素. + ++ 优点: 实现简单直观. ++ 缺点: `std::vector` 的删除操作 (`erase`) 时间复杂度为 O(N), 因为需要移动被删除元素之后的所有元素. 在本题中, 每次淘汰都需要进行一次 `erase`, 总共进行 `n` 次淘汰. 每一轮淘汰中可能包含多次删除. 总体时间复杂度会非常高, 远超 O(N^2), 对于 `n` 达到 `2e6` 的规模会超时. + +#### 2. `std::list` 或自定义链表 (优化方法) + +`main.cpp` 中的实现采用了自定义的单向链表 (`LISTNODE::ListNode`). 链表是解决此类问题的理想选择, 因为它的删除操作非常高效. + ++ 优点: + + 高效删除: 只要有指向待删除节点前一个节点的指针, 删除操作的时间复杂度就是 O(1). + + 模拟直观: 链表的结构天然适合模拟队列中元素的移除. + ++ 算法流程: + 1. 构建链表: 创建一个包含 `n` 个节点的链表, 节点值从 1 到 `n`. + 2. 模拟淘汰: + + 使用一个 `while` 循环, 条件是链表不为空 (`stable.next != nullptr`). + + 在每一轮淘汰中, 使用两个指针: `pre` 指向当前节点的前一个节点, `now` 指向当前节点. + + 从链表头开始, 步进 `m` 次来找到要淘汰的节点. + + 找到后, 将该节点的值存入结果数组, 然后通过 `pre->next = now->next` 来 "跳过" `now` 节点, 实现删除. + + 释放被删除节点的内存 (`delete now`). + + 这个过程在每一轮中重复, 直到当前轮次无法再步进 `m` 次. + + 然后外层 `while` 循环继续, 开始新一轮的淘汰, 直到链表为空. + +#### 3. 特殊情况处理 (`m = 1`) + +代码中对 `m = 1` 的情况做了特殊处理. 如果 `m = 1`, 意味着每次都淘汰第一个人, 所以淘汰顺序就是 `1, 2, 3, ..., n`. 这种情况可以直接生成结果, 避免了复杂的模拟, 提高了效率. + +### 结论 + +实现采用 模拟法, 并通过 自定义链表 优化了删除操作的效率, 从而将整体时间复杂度控制在可接受范围内 diff --git a/algorithm/2021F/lab_04/lab_04_B/lab_04_B.cpp b/algorithm/2021F/lab_04/lab_04_B/main.cpp similarity index 80% rename from algorithm/2021F/lab_04/lab_04_B/lab_04_B.cpp rename to algorithm/2021F/lab_04/lab_04_B/main.cpp index 0b02f524..9820a96c 100644 --- a/algorithm/2021F/lab_04/lab_04_B/lab_04_B.cpp +++ b/algorithm/2021F/lab_04/lab_04_B/main.cpp @@ -1,33 +1,7 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: 2020-2025 nanoseeds -/* - *@题目描述 - * 甲 个学生排成一排 - * 按下列算法踢人 - * 一直 开 行列有人 小 - * 赋 行列之长 于 冷 - * 赋 一 于 爱 - * 一直 开 爱 不大于 冷 毕 - * 踢出 队列 之 爱 - * 爱 自增 MU - *@输入 - * nu,int32_t [n,2*10^6] - * mu,int32_t [1,10] - *@输出 - * 踢人的顺序 - *@样例 - * 输入:`5 2` - * 输出:`1 3 5 2 4` - * 分析: - * NU=5,MU=2 - * 1 <= 2 <= 10 - * 2 <= 5 <= 2000000 - * 首先排列 `1 2 3 4 5` - * 第一轮踢掉`1,3,5` 留下`2,4` - * 第二轮踢掉`2` 留下`4` - * 第三轮踢掉`4` -please find the going-out order of student. - * */ + + //@Tag Done diff --git a/algorithm/2021F/lab_04/lab_04_B/lab_04_B_test.cpp b/algorithm/2021F/lab_04/lab_04_B/test.cpp similarity index 98% rename from algorithm/2021F/lab_04/lab_04_B/lab_04_B_test.cpp rename to algorithm/2021F/lab_04/lab_04_B/test.cpp index 05e1b242..77e48280 100644 --- a/algorithm/2021F/lab_04/lab_04_B/lab_04_B_test.cpp +++ b/algorithm/2021F/lab_04/lab_04_B/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_04_B.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_04/lab_04_B/resource/"; } diff --git a/algorithm/2021F/lab_04/lab_04_C/CMakeLists.txt b/algorithm/2021F/lab_04/lab_04_C/CMakeLists.txt index 5de3f24f..f07d2e4c 100644 --- a/algorithm/2021F/lab_04/lab_04_C/CMakeLists.txt +++ b/algorithm/2021F/lab_04/lab_04_C/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_04/lab_04_C/README.md b/algorithm/2021F/lab_04/lab_04_C/README.md new file mode 100644 index 00000000..0c2f8383 --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_C/README.md @@ -0,0 +1,84 @@ +--- +SPDX-License-Identifier: CC-BY-NC-SA-4.0 +--- + +# lab_04_C + +## Description + +There are n chains, each chain has a single node with a weight value. We will connect two chains by a sequence of p operations. Each operation connects chain a to chain b by attaching the head of chain b as the tail of chain a. After all operations, for each original node i (1..n) that is currently the head of a chain and the chain has at least q nodes, print the weight of the q-th node in that chain. Output all such weights separated by spaces. + +## Input + +The first line contains three integers n, p, q (1 < n, p < 1e6, 0 < q < 10). +The next line contains n integers representing the initial weight of node 1..n. +Following are p lines, each with two integers a b meaning connect chain a and b (attach head of b to tail of a). It is guaranteed that a and b are both current chain heads when the operation is applied. + +## Output + +For each node from 1 to n, if the node is the head of a chain and that chain has at least q nodes, output the weight of the q-th node in that chain (space separated). + +## Sample + +### Sample Input + +```text +5 3 2 +1 2 3 4 5 +1 3 +1 4 +2 5 +``` + +### Sample Output + +```text +3 5 +``` + +## 解题思路 + +### 问题分析 + +题目要求模拟自行车链条的连接过程. 初始时, 有 `n` 个独立的链粒 (节点), 每个链粒自身构成一个长度为 1 的链条. 接下来有 `p` 次操作, 每次操作将一个链条 (以 `b` 为头) 连接到另一个链条 (以 `a` 为头) 的末尾. 操作完成后, 需要遍历所有初始的链粒, 如果某个链粒 `i` 仍然是它所在链条的头, 并且该链条的长度不小于 `q`, 那么就输出该链条中第 `q` 个节点的权重. + +### 数据结构与算法 + +为了高效地模拟链条的连接和查询, 我们需要一种能够快速找到链条尾部以及支持节点连接的数据结构. `main.cpp` 的实现采用了 自定义链表 结合 辅助数组 的策略. + +1. 节点表示: + + 使用 `LISTNODE::ListNode` 结构体来表示每个链粒, 其中包含权重 `val` 和指向下一个节点的指针 `next`. + + 初始时, 创建一个 `std::vector nodes` 来存储 `n` 个链粒的指针, 每个链粒的 `next` 指针都为 `nullptr`. + +2. 快速定位链尾: + + 链条连接操作 `a->next = b` 需要找到链条 `a` 的尾部. 如果每次都从头遍历链条 `a` 来找尾部, 当链条很长时, 这个操作会非常耗时, 导致总体性能下降. + + 为了优化这一点, 代码引入了一个辅助数组 `std::vector to_tail`. `to_tail[i]` 存储以 `i+1` 号节点为 初始头节点 的链条的 当前尾节点指针. + + 这样, 当需要连接链条 `a` 和 `b` 时, 可以通过 `to_tail[a-1]` 直接获得链条 `a` 的尾节点, 时间复杂度为 O(1). + +3. 算法流程: + + 初始化: + + 读取 `n`, `p`, `q`. + + 创建 `n` 个 `ListNode` 节点, 并读入它们的权重, 存放在 `nodes` 数组中. + + 创建 `to_tail` 数组, 并将其初始化为与 `nodes` 相同, 因为初始时每个链条都只有一个节点, 头尾是同一个. + + 执行连接操作: + + 遍历 `p` 次操作. 对于每次操作 `a, b`: + + 获取链条 `a` 的尾节点: `fir_tail = to_tail[a-1]`. + + 获取链条 `b` 的头节点: `rih_head = nodes[b-1]`. + + 获取链条 `b` 的尾节点: `rih_tail = to_tail[b-1]`. + + 执行连接: `fir_tail->next = rih_head`. + + 更新 `to_tail` 数组: + + 链条 `a` 的新尾节点现在是原链条 `b` 的尾节点: `to_tail[a-1] = rih_tail`. + + 链条 `b` 不再是独立的链条 (它被合并了), 所以将其在 `to_tail` 中的记录置空: `to_tail[b-1] = nullptr`. 这也巧妙地标记了节点 `b` 不再是头节点. + + 查询与输出: + + 遍历所有初始节点 (从 0 到 `n-1`). + + 检查 `to_tail[i]` 是否为 `nullptr`. 如果不是, 说明节点 `i+1` 仍然是一个链条的头. + + 从这个头节点 `nodes[i]` 开始, 向后遍历 `q-1` 步, 找到第 `q` 个节点. + + 如果在此过程中链条没有提前结束 (即链条长度 `>= q`), 就将第 `q` 个节点的权重存入结果数组. + + 最后, 按格式输出结果数组中的所有权重. + +4. 资源管理: + + 由于代码中使用了 `new` 来动态分配 `ListNode` 节点的内存, 因此在程序结束前, 需要一个 `destoryResource` 函数来遍历并 `delete` 所有已分配的节点, 避免内存泄漏. + +### 结论 + +该实现通过引入一个辅助数组 `to_tail` 来记录每个链条的尾节点, 将链条连接操作的时间复杂度从 O(L) (L为链条长度) 优化到了 O(1). 最终的查询阶段是对每个作为头节点的链条进行一次遍历, 最多遍历 `q` 步. 整体算法高效, 能够处理大规模数据. diff --git a/algorithm/2021F/lab_04/lab_04_C/lab_04_C.cpp b/algorithm/2021F/lab_04/lab_04_C/main.cpp similarity index 99% rename from algorithm/2021F/lab_04/lab_04_C/lab_04_C.cpp rename to algorithm/2021F/lab_04/lab_04_C/main.cpp index bfecda43..73cb1269 100644 --- a/algorithm/2021F/lab_04/lab_04_C/lab_04_C.cpp +++ b/algorithm/2021F/lab_04/lab_04_C/main.cpp @@ -59,7 +59,7 @@ struct ListNode { #pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") #pragma GCC optimize("inline-small-functions") #pragma GCC optimize("-finline-small-functions") -#pragma GCC target("mmx") +#pragma GCC target("tune=native") #endif //ALGORITHM_TEST_MACRO #include diff --git a/algorithm/2021F/lab_04/lab_04_C/lab_04_C_test.cpp b/algorithm/2021F/lab_04/lab_04_C/test.cpp similarity index 98% rename from algorithm/2021F/lab_04/lab_04_C/lab_04_C_test.cpp rename to algorithm/2021F/lab_04/lab_04_C/test.cpp index e41a9f71..4e008ed9 100644 --- a/algorithm/2021F/lab_04/lab_04_C/lab_04_C_test.cpp +++ b/algorithm/2021F/lab_04/lab_04_C/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_04_C.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_04/lab_04_C/resource/"; } diff --git a/algorithm/2021F/lab_04/lab_04_D/CMakeLists.txt b/algorithm/2021F/lab_04/lab_04_D/CMakeLists.txt index dce330ce..564aeae5 100644 --- a/algorithm/2021F/lab_04/lab_04_D/CMakeLists.txt +++ b/algorithm/2021F/lab_04/lab_04_D/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_04/lab_04_D/README.md b/algorithm/2021F/lab_04/lab_04_D/README.md new file mode 100644 index 00000000..ee2e2ac0 --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_D/README.md @@ -0,0 +1,91 @@ +# lab_04_D — Minimum Weight Differences + +## Description + +Given a sequence `a` with `n` items, the weights of each item are `a[i]`. +We define the minimum weight difference of `a[i]` as `h[i] = min_{j>i} |a[j] - a[i]|`. + +Please compute the minimum weight difference of each item. + +### Input + +The first line has an integer `n` (2 <= `n` <= 2×10^6). + +The second line has `n` space-separated integers: `a1, a2, …, an` (1 <= `a[i]` <= 10^9). + +### Output + +Print space-separated integers: +`h1 h2 … h_{n-1}`. + +### Sample Input + +```log +5 +1 2 3 4 5 +``` + +### Sample Output + +```log +1 1 1 1 +``` + +### HINT + +It can be solved in a simple and efficient way by using sorting and an auxiliary linked-list-like structure. Please note that the size of input might be really large, so use efficient input methods. + +## 解题思路 + +### 问题分析 + +题目要求计算一个序列 `a` 中每个元素 `a[i]` 的 "最小权重差". 这个差值 `h[i]` 定义为在 `a[i]` 右侧的所有元素 `a[j]` (其中 `j > i`) 与 `a[i]` 的差的绝对值中的最小值. 即 `h[i] = min_{j>i} |a[j] - a[i]|`. + +一个朴素的想法是对于每个 `a[i]`, 都向后遍历 `a[i+1]` 到 `a[n-1]`, 找到差值最小的那个. 这种方法的时间复杂度是 O(N^2), 对于 `N` 高达 `2*10^6` 的数据规模, 显然会超时. + +我们需要一个更高效的算法. 关键在于, 对于 `a[i]`, 我们要找的 `a[j]` 是在数值上最接近 `a[i]` 的. 这启发我们从已处理过的元素集合中寻找 `a[i]` 的前驱 (小于 `a[i]` 的最大值) 和后继 (大于 `a[i]` 的最小值). + +### 算法设计 + +`main.cpp` 中的实现采用了一个非常巧妙的策略: 从后向前遍历序列, 并使用一个能够动态维护有序集合的数据结构. + +1. 遍历顺序: 从 `a[n-1]` 到 `a[0]` 倒序遍历. 当我们处理 `a[i]` 时, 我们需要的数据 `a[j]` (其中 `j > i`) 正是那些已经被我们遍历过并放入数据结构中的元素. + +2. 数据结构选择: 我们需要一个数据结构, 它能够: + + 高效地插入一个新元素. + + 高效地查找一个给定值的前驱和后继. + + `main.cpp` 实现了一个 AVL树 (自平衡二叉搜索树). + + 插入 (insert): AVL树的插入操作通过旋转来维持树的平衡, 时间复杂度为 O(log M), 其中 M 是树中元素的数量. + + 查找前驱/后继 (getPreNode/getNextNode): 在平衡二叉搜索树中, 查找一个值的前驱和后继也是 O(log M) 的操作. + +3. 算法流程: + + 创建一个空的 AVL 树. + + 从 `i = n-2` 向下遍历到 `0`. (注意, `a[n-1]` 没有右侧元素, 所以不需要计算). + + 在处理 `a[i]` 之前, 先将 `a[i+1]` 到 `a[n-1]` 的所有元素插入到 AVL 树中. + + 对于当前的 `a[i]`, 在 AVL 树中查找它的前驱 (`prev`) 和后继 (`next`). + + `h[i]` 的值就是 `min(|a[i] - prev.val|, |a[i] - next.val|)`. + + 如果前驱或后继不存在, 就只考虑存在的那一个. + + 将计算出的 `h[i]` 存入结果数组. + + 为了实现这个逻辑, 代码从 `a[n-1]` 开始, 每次迭代处理一个元素 `*iter`, 先将其插入树中, 然后为 `*(iter-1)` 计算最小差值. + +4. 代码实现细节: + + `cal` 函数中, 首先将序列的最后一个元素 `*data.crbegin()` 插入 AVL 树. + + 然后使用反向迭代器 `crbegin() + 1` 开始循环, 每次迭代处理一个新的元素 `*iter`. + + 在循环中, 先将 `*iter` 插入树中. + + 然后调用 `tree.getPreNode(*iter)` 和 `tree.getNextNode(*iter)` 来找到前驱和后继. + + 计算最小差值并存入 `will_return` 数组. + + `std::unordered_set` 用于处理重复元素, 如果一个元素已经存在, 它的最小差值为0. + + 最后, 由于结果是倒序计算的, 输出时需要再次反向遍历 `will_return` 数组. + +### 结论 + +通过 从后向前遍历 并结合 AVL树 这种高效的动态有序集合数据结构, 该算法成功地将每次查找最小差值的时间复杂度从 O(N) 降到了 O(log N), 使得总时间复杂度为 O(N log N), 这足以在规定时间内处理大规模数据. + +## 复用信息 + ++ Contest 1118:CS203 2022 Fall Lab 3 LinkedList ++ Contest 1119:CS217 2022 Fall Lab 3 LinkedList ++ Contest 1097:CS203 2021 Fall Lab 04 LinkedList ++ Contest 1098:CS217 2021 Fall Lab 04 LinkedList ++ Contest 1141:CS203 2023 Fall Lab 3 LinkedList diff --git a/algorithm/2021F/lab_04/lab_04_D/lab_04_D.cpp b/algorithm/2021F/lab_04/lab_04_D/main.cpp similarity index 100% rename from algorithm/2021F/lab_04/lab_04_D/lab_04_D.cpp rename to algorithm/2021F/lab_04/lab_04_D/main.cpp diff --git a/algorithm/2021F/lab_04/lab_04_D/lab_04_D_test.cpp b/algorithm/2021F/lab_04/lab_04_D/test.cpp similarity index 98% rename from algorithm/2021F/lab_04/lab_04_D/lab_04_D_test.cpp rename to algorithm/2021F/lab_04/lab_04_D/test.cpp index 5416b01c..18cf9d60 100644 --- a/algorithm/2021F/lab_04/lab_04_D/lab_04_D_test.cpp +++ b/algorithm/2021F/lab_04/lab_04_D/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_04_D.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_04/lab_04_D/resource/"; } diff --git a/algorithm/2021F/lab_04/lab_04_E/CMakeLists.txt b/algorithm/2021F/lab_04/lab_04_E/CMakeLists.txt new file mode 100644 index 00000000..f6252ecc --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_E/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER E) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_04/lab_04_E/README.md b/algorithm/2021F/lab_04/lab_04_E/README.md new file mode 100644 index 00000000..e16b2acb --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_E/README.md @@ -0,0 +1,61 @@ +# lab_04_E — Delete Decreasing Numbers + +## Description + +Given a sequence `{a[i]}` of length `n`, we define `a[i]` as a decreasing number if `a[i-1] > a[i]` (when `i-1 >= 1`) or `a[i] > a[i+1]` (when `i+1 <= n`). + +Please process the given sequence by deleting the decreasing numbers in it. In each turn you should delete all the decreasing numbers in the sequence at the same time. Repeat the procedure until the sequence has no decreasing numbers. + +### Input + +The first line of input contains an integer `T` (1 <= `T` <= 10) which is the number of test cases. + +For each test case, there are two lines. The first line contains an integer `n` (n <= 100000). + +The second line contains `n` integers representing the sequence `{a[i]}` (1 <= `a[i]` <= 100000). + +### Output + +One line per test case representing the final result sequence. + +### Sample Input + +```log +2 +10 +1 4 4 3 2 8 9 4 5 7 +5 +1 8 6 2 4 +``` + +### Sample Output + +```log +1 4 7 +1 4 +``` + +## 复用信息 + ++ Contest 1097:CS203 2021 Fall Lab 04 LinkedList ++ Contest 1098:CS217 2021 Fall Lab 04 LinkedList ++ Contest 1141:CS203 2023 Fall Lab 3 LinkedList + +## Analysis + +我们把序列维护为一个用两个索引数组表示的双向链表。 + +所有违反非降(non-decreasing)规则的索引都会被入队,并带上它们应当被删除的轮次(以保证同一轮同时删除)。 + +当一个元素被删除时,我们将其左右邻居重新连接;如果连接后某个邻居变成了递减数,则把它安排在下一轮删除(入队)。 + +当队列为空时,我们从第一个存活的索引开始遍历双向链表,收集剩下的元素作为结果。 + +该算法对每个索引只做常数次处理,所以每个测试用例的时间复杂度为 O(n),空间复杂度为 O(n)。 + +## Algorithm Analysis (实现说明) + ++ 思路: 使用两个数组 prev/next 模拟双向链表并维护一个当前需要删除的索引队列。初始时将所有“递减数”(与左右邻居不满足非降条件的索引)加入队列。每一轮中把队列内所有索引同时标记为删除,并把每个连续删除段的左右活跃邻居桥接起来。桥接后检查受影响的左右邻居是否在下一轮成为递减数并加入下一轮队列。重复直到没有待删元素。 ++ 实现要点: prev/next 用于 O(1) 删除和跳过已删除元素;用 removed 标记已删除,in_next 防止下一轮重复入队。对连续段一次性桥接能保证同时删除语义。 ++ 复杂度: 每个元素最多被删除一次,且每个邻接关系只更新常数次,时间 O(n),空间 O(n)。 ++ 边界: n<=1 时直接返回原序列;所有元素相等或严格非降序时无需删除,马上终止。 diff --git a/algorithm/2021F/lab_04/lab_04_E/main.cpp b/algorithm/2021F/lab_04/lab_04_E/main.cpp new file mode 100644 index 00000000..0eac1923 --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_E/main.cpp @@ -0,0 +1,216 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_04_E { +#endif +using std::cin; +using std::cout; +using std::vector; +using std::set; +static constexpr const char end{'\n'}; + +using num_t = int32_t; + +struct test_case final { + num_t length{0}; + vector values{}; + + test_case() = default; + + test_case(num_t l, vector &&v) : length(l), values(std::move(v)) { + } +}; + +using input_type = vector; +using output_type = vector >; + +inline input_type read(); + +output_type cal(const input_type &data); + +void output(const output_type &data); + +vector solve_case(const vector &numbers); + +int main() { + const auto input_data = read(); + const auto output_data = cal(input_data); + output(output_data); + return 0; +} + +inline input_type read() { + num_t total_cases{0}; + cin >> total_cases; + input_type all_cases{}; + all_cases.reserve(total_cases); + for (num_t case_idx{0}; case_idx < total_cases; ++case_idx) { + num_t length{0}; + cin >> length; + vector values(static_cast::size_type>(length)); + for (num_t i{0}; i < length; ++i) { + cin >> values[static_cast::size_type>(i)]; + } + all_cases.push_back(test_case{length, std::move(values)}); + } + return all_cases; +} + +output_type cal(const input_type &data) { + output_type answers{}; + answers.reserve(data.size()); + for (const auto &item: data) { + answers.emplace_back(solve_case(item.values)); + } + return answers; +} + +void output(const output_type &data) { + for (const auto &sequence: data) { + bool first{true}; + for (const auto value: sequence) { + if (!first) { + cout << ' '; + } + first = false; + cout << value; + } + cout << end; + } +} + +vector solve_case(const vector &numbers) { + const int32_t n = static_cast(numbers.size()); + if (n <= 1) return numbers; + + vector prev(n), next(n); + for (int32_t i = 0; i < n; ++i) { + prev[i] = i - 1; + next[i] = i + 1; // next[n-1] == n 作为右侧哨兵 + } + + vector removed(n, 0); + + // 初始候选:所有下降数 + vector cur; + cur.reserve(n); + for (int32_t i = 0; i < n; ++i) { + bool has_left = (i - 1) >= 0 && numbers[(size_t) (i - 1)] > numbers[(size_t) i]; + bool has_right = (i + 1) < n && numbers[(size_t) i] > numbers[(size_t) (i + 1)]; + if (has_left || has_right) cur.push_back(i); + } + + vector nxt; + nxt.reserve(n); + vector in_next(n, 0); // 下一轮去重 + + while (!cur.empty()) { + std::sort(cur.begin(), cur.end()); + cur.erase(std::unique(cur.begin(), cur.end()), cur.end()); + + // 标记本轮删除 + for (int32_t idx: cur) removed[idx] = 1; + + nxt.clear(); + + // 按连续段 [L..R] 同时桥接 + int32_t k = 0; + while (k < (int32_t) cur.size()) { + int32_t L = cur[k]; + int32_t R = L; + while (k + 1 < (int32_t) cur.size() && cur[k + 1] == R + 1) { + ++k; + R = cur[k]; + } + ++k; + + // 找到段左、右侧仍存活的邻居 + int32_t left = prev[L]; + while (left >= 0 && removed[left]) left = prev[left]; + + int32_t right = (R + 1 < n) ? (R + 1) : n; + // 使用 next[R] 更稳妥,但 R+1 == next[R] 初始等价 + // 若 right 是活的就用 right,否则跳过至右侧活的 + if (right < n) { + if (removed[right]) { + // 跳过右侧本轮被删的连续段 + while (right < n && removed[right]) right = next[right]; + } + } + + // 桥接 + if (left >= 0) next[left] = right; + if (right < n) prev[right] = left; + + // 段左邻居可能因桥接变成下降数 + if (left >= 0 && !removed[left] && !in_next[left]) { + int32_t ll = prev[left]; + while (ll >= 0 && removed[ll]) ll = prev[ll]; + int32_t rr = next[left]; + while (rr < n && removed[rr]) rr = next[rr]; + if ((ll >= 0 && numbers[(size_t) ll] > numbers[(size_t) left]) || + (rr < n && numbers[(size_t) left] > numbers[(size_t) rr])) { + in_next[left] = 1; + nxt.push_back(left); + } + } + + // 段右邻居可能因桥接变成下降数 + if (right < n && !removed[right] && !in_next[right]) { + int32_t ll = prev[right]; + while (ll >= 0 && removed[ll]) ll = prev[ll]; + int32_t rr = next[right]; + while (rr < n && removed[rr]) rr = next[rr]; + if ((ll >= 0 && numbers[(size_t) ll] > numbers[(size_t) right]) || + (rr < n && numbers[(size_t) right] > numbers[(size_t) rr])) { + in_next[right] = 1; + nxt.push_back(right); + } + } + } + + // 清理下一轮去重标记(仅对已加入的元素) + for (int32_t j: nxt) in_next[j] = 0; + + cur.swap(nxt); + } + + // 输出存活元素(按原顺序) + vector result; + result.reserve(n); + for (int32_t i = 0; i < n; ++i) { + if (!removed[i]) result.push_back(numbers[(size_t) i]); + } + return result; +} + +static const auto faster_streams = [] { + std::srand(static_cast(std::time(nullptr))); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_04/lab_04_E/resource/1.data.in b/algorithm/2021F/lab_04/lab_04_E/resource/1.data.in new file mode 100644 index 00000000..0e81ec4a --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_E/resource/1.data.in @@ -0,0 +1,5 @@ +2 +10 +1 4 4 3 2 8 9 4 5 7 +5 +1 8 6 2 4 diff --git a/algorithm/2021F/lab_04/lab_04_E/resource/1.data.out b/algorithm/2021F/lab_04/lab_04_E/resource/1.data.out new file mode 100644 index 00000000..1f9049f9 --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_E/resource/1.data.out @@ -0,0 +1,2 @@ +1 4 7 +1 4 diff --git a/algorithm/2021F/lab_04/lab_04_E/test.cpp b/algorithm/2021F/lab_04/lab_04_E/test.cpp new file mode 100644 index 00000000..d8645ffe --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_E/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_04/lab_04_E/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_04_E { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 04_E]", "[test 04_E]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_04/lab_04_F/CMakeLists.txt b/algorithm/2021F/lab_04/lab_04_F/CMakeLists.txt new file mode 100644 index 00000000..3bd8bb2b --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_F/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER F) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_04/lab_04_F/README.md b/algorithm/2021F/lab_04/lab_04_F/README.md new file mode 100644 index 00000000..400c636e --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_F/README.md @@ -0,0 +1,107 @@ +# lab_04_F — String Operations (Insert / Find / Transform) + +> Time Limit: 2 Sec Memory Limit: 128 MB + +## Description + + Given a string S and three operators: + ++ Insert(ch, p), inserting the char ch to position p. ++ Find(p), finding the char at position p and print it to screen. ++ Transform(l,r), transforming the characters from position l to position r (including l, r) (we define transforming as for each character c in l to r we apply ('a' + 'z' - c) to transform it) + + +## Input + +The first line has a string S + +The second line has an integer n, which is the number of operations. + +The next n lines are one operation per line. + +For each presentation, we use 1 for Insert , 2 for Find, 3 for Transform. (len(S) <= 2000000, n <= 100000) + +## Output + +Follow the output definition of each operation. + +### Sample Input + +```log +madamimadam +5 +1 b 1 +1 b 2 +2 3 +3 1 3 +2 2 +``` + +### Sample Output + +```log +m +y +``` + +### HINT + +You are likely to encounter TLE in this question, which is normal. + +Use a more efficient linked-list or balanced data structure (for example, a well-implemented rope, splay, or a custom linked structure) to meet time limits. + +## 解题思路 + +### 问题分析 + +本题要求对一个字符串进行三种操作: +1. Insert(ch, p): 在位置 `p` 插入字符 `ch`. +2. Find(p): 查找并输出位置 `p` 的字符. +3. Transform(l, r): 对 `[l, r]` 区间内的所有字符 `c` 应用转换规则 `'a' + 'z' - c`. + +字符串的长度和操作次数都很大, 这意味着我们需要一个能够高效处理这些操作的数据结构. 简单的 `std::string` 或 `std::vector` 在 `Insert` 操作上效率低下 (O(N)), 会导致超时. + +### 数据结构选择: Implicit Treap (无旋Treap) + +`main.cpp` 的实现采用了一种高级数据结构——Implicit Treap (无旋Treap或分裂合并Treap). 这种数据结构非常适合处理序列上的区间操作. + ++ Implicit (隐式): 节点的顺序由其在树中的中序遍历位置决定, 而不是由键值决定. 这使得它能像数组一样通过索引访问元素. ++ Treap: 每个节点除了有值之外, 还有一个随机生成的 优先级 (priority). 整个数据结构同时满足 二叉搜索树 (BST) 的性质 (按中序遍历位置) 和 堆 的性质 (按优先级). 这两个性质共同保证了树的期望高度为 O(log N), 从而确保了操作的高效性. + +#### 核心操作: `split` 和 `merge` + +Implicit Treap 的所有操作都基于两个基本原子操作: +1. `split(T, k, &L, &R)`: 将树 `T` 分裂成两棵树 `L` 和 `R`. `L` 包含原树中序遍历的前 `k` 个节点, `R` 包含剩下的节点. +2. `merge(L, R)`: 将树 `L` 和树 `R` 合并成一棵新树, 前提是 `L` 中的所有节点在中序遍历中都位于 `R` 的所有节点之前. + +这两个操作的时间复杂度都与树的高度成正比, 即 O(log N). + +### 算法实现 + +1. 节点 (Node): + + `ch`: 存储字符. + + `prio`: 随机优先级. + + `sz`: 以该节点为根的子树的大小 (包括自身). 这是实现按位置分裂的关键. + + `flip`: 懒惰标记 (Lazy Tag). 用于 `Transform` 操作. 当 `flip` 为 `true` 时, 表示该节点及其子树需要进行字符翻转. + + `l`, `r`: 左右子节点指针. + +2. 操作实现: + + `Insert(ch, p)`: + 1. 使用 `split` 将树分裂成两部分: `[1, p-1]` 和 `[p, end]`. + 2. 创建一个新节点 `M` 来存储字符 `ch`. + 3. 使用 `merge` 将三部分重新组合: `merge(merge(L, M), R)`. + + `Find(p)`: + + 这是一个标准的在二叉搜索树中查找第 `k` 大元素的操作. 从根节点开始, 比较 `p` 和左子树的大小 `size(t->l)`, 决定向左走还是向右走, 直到找到目标节点. 时间复杂度 O(log N). + + `Transform(l, r)`: + 1. 使用 `split` 将树分解成三部分: `A = [1, l-1]`, `B = [l, r]`, `C = [r+1, end]`. + 2. 对中间部分 `B` 的根节点应用懒惰标记: `apply_inv(B)`. 这个函数会翻转根节点的 `flip` 标志, 并更新其字符. + 3. 懒惰传播 (Push Down): `apply_inv` 只修改根节点. 当我们后续需要访问子节点时 (例如在 `split` 或 `merge` 过程中), `push` 函数会被调用, 将父节点的 `flip` 标记下推给子节点, 并清空父节点的标记. 这确保了标记最终能应用到所有相关节点, 同时避免了一次性更新整个区间的巨大开销. + 4. 将三部分重新合并: `merge(A, merge(B, C))`. + +3. 构建与内存管理: + + `build_from_string`: 为了高效地从初始字符串构建 Treap, 代码使用了一种 O(N) 的建树算法, 该算法利用单调栈来模拟笛卡尔树的构建过程. + + 内存池: 为了避免频繁的 `new` 和 `delete` 带来的开销和内存碎片, 代码使用了一个 `std::vector` 作为内存池 (`node_pool`), 通过一个指针 `pool_ptr` 进行快速分配. + +### 结论 + +通过使用 Implicit Treap 这种强大的数据结构, `main.cpp` 将所有操作的时间复杂度都优化到了 O(log N) (期望), 从而能够轻松应对本题的数据规模. 懒惰标记的应用是高效处理区间更新的关键. diff --git a/algorithm/2021F/lab_04/lab_04_F/main.cpp b/algorithm/2021F/lab_04/lab_04_F/main.cpp new file mode 100644 index 00000000..1e0c0fcb --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_F/main.cpp @@ -0,0 +1,298 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ALGORITHM_TEST_MACRO +namespace lab_04_F { +#endif + +using std::cin; +using std::tie; +using std::cout; +using std::tuple; +using std::string; +using std::vector; + +static constexpr const char end{'\n'}; + +using num_t = int32_t; + +struct Operation { + int type; // 1: Insert, 2: Find, 3: Transform + char ch; // used for Insert + num_t p; // used for Insert/Find + num_t l, r; // used for Transform +}; + +using input_type = std::tuple >; +using output_type = string; + +inline input_type read(); + +output_type cal(const input_type &data); + +void output(const output_type &data); + +// Implicit Treap with lazy "invert" ('a' + 'z' - c) on range +struct Node { + char ch; + uint32_t prio; + int sz; + bool flip; // lazy invert flag + Node *l, *r; +}; + +static vector node_pool; +static int pool_ptr = 0; + +inline uint32_t rng() { + static uint32_t x = uint32_t(time(nullptr)) ^ 0x9e3779b9U; + // xorshift32 + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + return x; +} + +inline Node *newNode(char c) { + Node &n = node_pool[pool_ptr++]; + n.ch = c; + n.prio = rng(); + n.sz = 1; + n.flip = false; + n.l = n.r = nullptr; + return &n; +} + +inline int size(Node *t) { return t ? t->sz : 0; } + +inline char invert_char(char c) { + // Defined: 'a' + 'z' - c + return char('a' + 'z' - c); +} + +inline void apply_inv(Node *t) { + if (!t) return; + t->flip ^= true; + t->ch = invert_char(t->ch); +} + +inline void push(Node *t) { + if (!t || !t->flip) return; + t->flip = false; + if (t->l) apply_inv(t->l); + if (t->r) apply_inv(t->r); +} + +inline void upd(Node *t) { + if (!t) return; + t->sz = 1 + size(t->l) + size(t->r); +} + +Node *merge(Node *a, Node *b) { + if (!a) return b; + if (!b) return a; + if (a->prio < b->prio) { + push(a); + a->r = merge(a->r, b); + upd(a); + return a; + } else { + push(b); + b->l = merge(a, b->l); + upd(b); + return b; + } +} + +// split t into [a (size=k), b] +void split(Node *t, int k, Node *&a, Node *&b) { + if (!t) { + a = b = nullptr; + return; + } + push(t); + int ls = size(t->l); + if (k <= ls) { + split(t->l, k, a, t->l); + upd(t); + b = t; + } else { + split(t->r, k - ls - 1, t->r, b); + upd(t); + a = t; + } +} + +char kth(Node *t, int k) { + Node *cur = t; + while (cur) { + push(cur); + int ls = size(cur->l); + if (k == ls + 1) return cur->ch; + if (k <= ls) cur = cur->l; + else { + k -= ls + 1; + cur = cur->r; + } + } + return '\0'; +} + +// Build treap from string in O(n) using Cartesian tree with priorities +Node *build_from_string(const string &s) { + if (s.empty()) return nullptr; + + vector st; + st.reserve(64); // small initial reserve + + for (size_t i = 0; i < s.size(); ++i) { + Node *cur = newNode(s[i]); + Node *last = nullptr; + while (!st.empty() && st.back()->prio > cur->prio) { + last = st.back(); + st.pop_back(); + } + cur->l = last; + if (!st.empty()) st.back()->r = cur; + st.push_back(cur); + } + Node *root = st.front(); + + // Compute sizes recursively (expected stack depth O(log n)) + // Avoids large auxiliary vectors + struct Helper { + static int dfs(Node *t) { + if (!t) return 0; + int ls = dfs(t->l); + int rs = dfs(t->r); + t->sz = 1 + ls + rs; + return t->sz; + } + }; + Helper::dfs(root); + return root; +} + +int main() { + auto input_data = read(); + const auto output_data = cal(input_data); + output(output_data); + return 0; +} + +inline input_type read() { + string S; + cin >> S; + int n; + cin >> n; + vector ops; + ops.reserve(n); + for (int i = 0; i < n; ++i) { + int t; + cin >> t; + Operation op{}; + op.type = t; + if (t == 1) { + char ch; + num_t p; + cin >> ch >> p; + op.ch = ch; + op.p = p; + } else if (t == 2) { + num_t p; + cin >> p; + op.p = p; + } else { + // t == 3 + num_t l, r; + cin >> l >> r; + op.l = l; + op.r = r; + } + ops.push_back(op); + } + return std::make_tuple(S, ops); +} + +output_type cal(const input_type &data) { + string S; + vector ops; + tie(S, ops) = data; + + // Pre-allocate pool: initial size + number of inserts + size_t insert_cnt = 0; + for (size_t i = 0; i < ops.size(); ++i) if (ops[i].type == 1) ++insert_cnt; + node_pool.clear(); + node_pool.resize(S.size() + insert_cnt + 8); // small safety margin + pool_ptr = 0; + + Node *root = build_from_string(S); + + string out; + out.reserve(ops.size() * 2); + + for (const auto & op : ops) { + if (op.type == 1) { + // Insert(ch, p): insert before position p (1-based). p can be size+1 to append + int p = op.p; + if (p < 1) p = 1; + int cur_sz = size(root); + if (p > cur_sz + 1) p = cur_sz + 1; + Node *L, *R; + split(root, p - 1, L, R); + Node *M = newNode(op.ch); + root = merge(merge(L, M), R); + } else if (op.type == 2) { + // Find(p): 1-based + int p = op.p; + char c = kth(root, p); + out.push_back(c); + out.push_back(end); + } else { + // Transform(l, r): invert chars in range [l, r] + int l = op.l, r = op.r; + if (l > r) continue; + l = std::max(l, 1); + r = std::min(r, size(root)); + if (l > r) continue; + Node *A, *B, *C; + split(root, l - 1, A, B); + split(B, r - l + 1, B, C); + apply_inv(B); + root = merge(A, merge(B, C)); + } + } + + return out; +} + +void output(const output_type &data) { + cout << data; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_04/lab_04_F/resource/1.data.in b/algorithm/2021F/lab_04/lab_04_F/resource/1.data.in new file mode 100644 index 00000000..d88c2fae --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_F/resource/1.data.in @@ -0,0 +1,7 @@ +madamimadam +5 +1 b 1 +1 b 2 +2 3 +3 1 3 +2 2 diff --git a/algorithm/2021F/lab_04/lab_04_F/resource/1.data.out b/algorithm/2021F/lab_04/lab_04_F/resource/1.data.out new file mode 100644 index 00000000..19b86de1 --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_F/resource/1.data.out @@ -0,0 +1,2 @@ +m +y diff --git a/algorithm/2021F/lab_04/lab_04_F/test.cpp b/algorithm/2021F/lab_04/lab_04_F/test.cpp new file mode 100644 index 00000000..1ca42866 --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_F/test.cpp @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_04/lab_04_F/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_04_F { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 04_F]", "[test 04_F]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_04/lab_04_G/CMakeLists.txt b/algorithm/2021F/lab_04/lab_04_G/CMakeLists.txt new file mode 100644 index 00000000..768dc1e2 --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_G/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER G) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_04/lab_04_G/README.md b/algorithm/2021F/lab_04/lab_04_G/README.md new file mode 100644 index 00000000..8c0f99af --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_G/README.md @@ -0,0 +1,96 @@ +# lab_04_G — Sum of Products of Largest and k-th Largest in Subarrays + +> Time Limit: 2 Sec Memory Limit: 128 MB + +## Description + +Given a sequence $\{a_i\}$ of length `n` where the sequence is a permutation of `[1..n]`. + +Define + +$$ +f(l,r,k)= +\begin{cases} +\text{the product of the largest and the $k$-th largest element in }\{a_l,\dots,a_r\}, & \text{if } r-l+1\ge k,\\ +0, & \text{if } r-l+1 我感觉这已经和链表没有任何关系了, 纯小众变态题目 + +## 解题思路 + +### 问题分析 + +本题要求对一个给定的排列, 计算所有子数组中最大元素与第 `k` 大元素的乘积之和. 由于子数组数量是 O(N^2), 对每个子数组都进行查找是不可行的. 因此, 需要转换思路, 从每个元素的贡献角度来计算总和. + +### 核心思想: 贡献法 + +我们不枚举子数组, 而是枚举每个元素 `v` (从 `n` 到 `1`), 并计算它在两种情况下的贡献: +1. 当 `v` 作为子数组的 第 `k` 大 元素时. +2. 当 `v` 作为子数组的 最大 元素时. + +由于题目要求的是最大值和第 `k` 大值的乘积, 直接计算一个元素作为第 `k` 大, 同时另一个元素作为最大的情况比较复杂. `main.cpp` 采用了一种更精妙的贡献法: 枚举每个值 `v` 作为第 `k` 大的场景, 同时确定该场景下的最大值, 并计算这样的子数组有多少个. + +### 算法流程 (从大到小枚举) + +代码实现采用从 `n` 到 `1` 的顺序遍历值 `v`. 当我们处理值 `v` 时, 所有比 `v` 大的值的位置都已经被记录下来. + +1. 预处理: + + 因为输入是 `1` 到 `n` 的排列, 我们可以创建一个 `pos` 数组, `pos[v]` 存储值 `v` 在原数组中的位置 (1-based index). 这使得我们可以 O(1) 地通过值找到其位置. + +2. 数据结构: + + 为了高效地找到一个位置 `p` 左右两边那些 值更大 的元素的位置, 代码使用了一个 `std::vector` 作为 位图 (bitset). 这个位图标记了哪些位置上的元素已经被处理过 (即值比当前 `v` 大). + +3. 主循环 (v 从 n 到 1): + + 对于当前值 `v`, 通过 `pos[v]` 找到其位置 `p`. + + 查找邻居: 在位图中, 查找位置 `p` 左侧和右侧最近的 `k` 个 "已激活" 的位置. 这些位置上的值都比 `v` 大. + + `Lpos` 数组存储左侧的 `k` 个邻居位置. + + `Rpos` 数组存储右侧的 `k` 个邻居位置. + + 为了加速查找, 代码使用了 `__builtin_clzll` (前导零计数) 和 `__builtin_ctzll` (末尾零计数) 这类位操作内建函数, 可以在 O(1) 时间内在 `uint64_t` 中找到最高/最低的置位, 从而快速定位到位图中的下一个邻居. + + 组合计数: + + 现在我们考虑以 `v` (在位置 `p`) 作为第 `k` 大元素的子数组. 这样的子数组必须包含 `v` 以及 `k-1` 个比 `v` 大的元素. + + 这 `k-1` 个较大的元素可以从 `p` 的左侧和右侧邻居中选取. 假设我们从左侧选 `u` 个, 从右侧选 `t` 个, 其中 `u + t = k - 1`. + + 对于一个固定的 `(u, t)` 组合, 子数组的左端点可以在 `Lpos[u+1]` 和 `Lpos[u]` 之间选择, 右端点可以在 `Rpos[t]` 和 `Rpos[t+1]` 之间选择. ( `Lpos[0]` 和 `Rpos[0]` 都是 `p`). + + 这样就可以计算出满足条件的子数组数量: `ways = (Lpos[u] - Lpos[u+1]) * (Rpos[t+1] - Rpos[t])`. + + 计算贡献: + + 对于上述 `ways` 个子数组, 第 `k` 大的元素是 `v`. + + 最大元素是 `v` 和它左右 `k-1` 个邻居中的最大值. 代码通过预计算邻居值的前缀最大值 (`maxLeft`, `maxRight`) 来快速得到 `mval = max(maxLeft[u], maxRight[t])`. + + 将贡献 `v * mval * ways` 累加到总和 `acc` 中. + + 更新位图: 将位置 `p` 在位图中标记为已激活. + +4. k=1 的特殊情况: + + 当 `k=1` 时, 问题退化为计算 `sum(max(sub_array)^2)`. + + 这是一个经典问题, 可以用 单调栈 在 O(N) 时间内解决. 对每个元素 `a[i]`, 找到它作为最大值的区间范围 (即左边第一个比它大的 `NL[i]` 和右边第一个比它大的 `NR[i]`). 那么 `a[i]` 作为最大值的子数组共有 `(i - NL[i]) * (NR[i] - i)` 个. + +### 结论 + +该算法通过贡献法, 将问题转化为一个精巧的组合计数问题. 利用从大到小的值序遍历, 并结合位图和位运算技巧高效查找邻居, 使得在处理每个值 `v` 时, 只需要 O(k) 的时间来计算其贡献. 总体时间复杂度为 O(N*k), 远优于朴素算法, 能够通过本题的数据范围. diff --git a/algorithm/2021F/lab_04/lab_04_G/main.cpp b/algorithm/2021F/lab_04/lab_04_G/main.cpp new file mode 100644 index 00000000..b29edae1 --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_G/main.cpp @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("avx,avx2,sse,sse2,sse3,ssse3,popcnt,abm,mmx,tune=native") +#else +namespace lab_04_G { +#endif + +using int32 = std::int32_t; +using int64 = std::int64_t; +static constexpr int64 MOD = 1000000007LL; + +struct TestCase { + int32 n, k; + std::vector a; +}; + +std::vector read_input(); + +std::vector solve(const std::vector &cases); + +void write_output(const std::vector &answers); + +inline int64 mod_mul64(int64 a, int64 b) { return (a * b) % MOD; } + +int32 main() { + const auto input_data = read_input(); + const auto results = solve(input_data); + write_output(results); + return 0; +} + +std::vector read_input() { + std::vector data; + + int32 T; + if (!(std::cin >> T)) return data; + data.reserve(T); + for (int32 _ = 0; _ < T; ++_) { + TestCase tc; + std::cin >> tc.n >> tc.k; + tc.a.resize(tc.n); + for (int32 i = 0; i < tc.n; ++i) std::cin >> tc.a[i]; + data.push_back(std::move(tc)); + } + return data; +} + +std::vector solve(const std::vector &cases) { + std::vector outputs; + outputs.reserve(cases.size()); + + for (const auto &tc: cases) { + const int32 n = tc.n, k = tc.k; + const auto &a = tc.a; + + // k == 1: sum of max^2 over all subarrays via nearest greater by value + if (k == 1) { + std::vector NL(n + 1, 0), NR(n + 1, n + 1); + std::vector st; + st.reserve(n); + for (int32 i = 1; i <= n; ++i) { + int32 ai = a[i - 1]; + while (!st.empty() && a[st.back() - 1] < ai) st.pop_back(); + NL[i] = st.empty() ? 0 : st.back(); + st.push_back(i); + } + st.clear(); + for (int32 i = 1; i <= n; ++i) { + while (!st.empty() && a[i - 1] > a[st.back() - 1]) { + NR[st.back()] = i; + st.pop_back(); + } + st.push_back(i); + } + uint64_t acc = 0ULL; + for (int32 i = 1; i <= n; ++i) { + int64 cnt = (int64) (i - NL[i]) * (NR[i] - i) % MOD; + int64 v = a[i - 1] % MOD; + acc += (uint64_t) mod_mul64(cnt, mod_mul64(v, v)); + } + outputs.push_back((int64) (acc % MOD)); + continue; + } + + // value -> position (permutation) + std::vector pos(n + 1); + for (int32 i = 1; i <= n; ++i) pos[a[i - 1]] = i; + + // bitset of active positions (value greater than current v) + const int W = 64; + const int words = (n + W - 1) / W; + std::vector bits(words, 0ULL); + + const int K1 = k - 1; + std::array Lpos{}, Rpos{}, maxLeft{}, maxRight{}, dL{}, dR{}; + + uint64_t acc = 0ULL; + + for (int32 v = n; v >= 1; --v) { + int32 p = pos[v]; + int32 aj = a[p - 1]; + int64 aj_mod = aj % MOD; + + // left neighbors: fill Lpos[1..k], Lpos[0]=p, rest 0 + Lpos[0] = p; { + int need = k, u = 1; + int idx = (p - 1) >> 6; + int off = (p - 1) & 63; + uint64_t mask = (off == 0) ? 0ULL : (bits[idx] & ((~0ULL) >> (64 - off))); + while (need > 0) { + while (need > 0 && mask) { + int msb = 63 - __builtin_clzll(mask); + int32 q = (idx << 6) + msb + 1; // back to 1-based + Lpos[u++] = q; + --need; + mask ^= (1ULL << msb); + } + if (need == 0) break; + if (--idx < 0) break; + mask = bits[idx]; + } + for (; u <= k; ++u) Lpos[u] = 0; + } + + // right neighbors: fill Rpos[1..k], Rpos[0]=p, rest n+1 + Rpos[0] = p; { + int need = k, t = 1; + int idx = (p - 1) >> 6; + int off = (p - 1) & 63; + uint64_t mask; + if (off == 63) mask = 0ULL; + else { + uint64_t lowMask = (1ULL << (off + 1)) - 1ULL; + mask = bits[idx] & (~lowMask); + } + while (need > 0) { + while (need > 0 && mask) { + int lsb = __builtin_ctzll(mask); + int32 q = (idx << 6) + lsb + 1; + Rpos[t++] = q; + --need; + mask &= (mask - 1); + } + if (need == 0) break; + if (++idx >= words) break; + mask = bits[idx]; + } + for (; t <= k; ++t) Rpos[t] = n + 1; + } + + // prefix maxima of neighbor values (only need up to K1) + maxLeft[0] = 0; + for (int u = 1; u <= K1; ++u) { + int32 q = Lpos[u]; + int32 val = (q == 0 ? 0 : a[q - 1]); + maxLeft[u] = std::max(maxLeft[u - 1], val); + } + maxRight[0] = 0; + for (int t = 1; t <= K1; ++t) { + int32 q = Rpos[t]; + int32 val = (q == n + 1 ? 0 : a[q - 1]); + maxRight[t] = std::max(maxRight[t - 1], val); + } + + // deltas for endpoints + for (int u = 0; u <= K1; ++u) dL[u] = Lpos[u] - Lpos[u + 1]; + for (int t = 0; t <= K1; ++t) dR[t] = Rpos[t + 1] - Rpos[t]; + + // accumulate contributions + for (int u = 0; u <= K1; ++u) { + int t = K1 - u; + int32 dl = dL[u], dr = dR[t]; + if (dl <= 0 || dr <= 0) continue; + + int32 mval = std::max(maxLeft[u], maxRight[t]); + if (mval == 0) continue; + + int64 ways = ((int64) dl * (int64) dr) % MOD; + int64 prod = mod_mul64(aj_mod, (int64) mval % MOD); + int64 term = mod_mul64(ways, prod); + acc += (uint64_t) term; + } + + // activate position p + int w = (p - 1) >> 6; + int b = (p - 1) & 63; + bits[w] |= (1ULL << b); + } + + outputs.push_back((int64) (acc % MOD)); + } + return outputs; +} + +void write_output(const std::vector &answers) { + for (auto v: answers) std::cout << v << '\n'; +} + +static const auto faster_streams = [] { + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} // namespace lab_04_G +#endif diff --git a/algorithm/2021F/lab_04/lab_04_G/resource/1.data.in b/algorithm/2021F/lab_04/lab_04_G/resource/1.data.in new file mode 100644 index 00000000..50833593 --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_G/resource/1.data.in @@ -0,0 +1 @@ +1 5 2 1 2 3 4 5 diff --git a/algorithm/2021F/lab_04/lab_04_G/resource/1.data.out b/algorithm/2021F/lab_04/lab_04_G/resource/1.data.out new file mode 100644 index 00000000..fd03ab2a --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_G/resource/1.data.out @@ -0,0 +1 @@ +130 diff --git a/algorithm/2021F/lab_04/lab_04_G/test.cpp b/algorithm/2021F/lab_04/lab_04_G/test.cpp new file mode 100644 index 00000000..e0dc5814 --- /dev/null +++ b/algorithm/2021F/lab_04/lab_04_G/test.cpp @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_04/lab_04_G/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_04_G { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 04_G]", "[test 04_G]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_05/CMakeLists.txt b/algorithm/2021F/lab_05/CMakeLists.txt index 4a088bae..eea8ffe1 100644 --- a/algorithm/2021F/lab_05/CMakeLists.txt +++ b/algorithm/2021F/lab_05/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -set(dependencies A B C D) +set(dependencies A B C D E F G) foreach (elementName IN LISTS dependencies) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${elementName}) endforeach () diff --git a/algorithm/2021F/lab_05/README.md b/algorithm/2021F/lab_05/README.md new file mode 100644 index 00000000..d4c27e5e --- /dev/null +++ b/algorithm/2021F/lab_05/README.md @@ -0,0 +1,33 @@ +# Contest1099 - CS203 2021 Fall Lab 05 Stack + Queue + +> cid: 1100 + +Welcome to CS203 2021 Fall Lab 05! Enjoy this Lab! + +There are six problems for you to solve. + +Score: + ++ A: 10 ++ B: 15/10 ++ C: 15/10 ++ D: 20/15 ++ E: 20/15 ++ F: 20 ++ G: undefined/20 + +Reading the samples and hints carefully can help you understand the problem. + +## 题目列表 + +| Problem | problem id | +|--------:|-----------:| +| A | 1443 | +| B | 1444 | +| C | 1357 | +| D | 1445 | +| E | 1342 | +| F | 1376 | +| G | 1369 | + +E, F, G 均被复用 diff --git a/algorithm/2021F/lab_05/cs203.submit.csv b/algorithm/2021F/lab_05/cs203.submit.csv new file mode 100644 index 00000000..506493aa --- /dev/null +++ b/algorithm/2021F/lab_05/cs203.submit.csv @@ -0,0 +1,8 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 239, 1, 537, 60, 16, 2, 341, 52, 1248, 5, 234, 1009 +B, 236, 502, 96, 1, 3, 113, 54, 1005, 25, 106, 874 +C, 250, 2, 106, 8, 3, 94, 46, 509, 31, 72, 406 +D, 226, 2, 574, 27, 3, 6, 54, 37, 929, 10, 202, 717 +E, 208, 377, 78, 138, 3, 346, 53, 1203, 3, 253, 947 +F, 113, 298, 332, 26, 1, 76, 37, 883, 5, 203, 675 +Total, 1272, 5, 2394, 601, 184, 18, 1024, 279, 5777, 79, 1070, 4628 diff --git a/algorithm/2021F/lab_05/cs217.submit.csv b/algorithm/2021F/lab_05/cs217.submit.csv new file mode 100644 index 00000000..9e84491c --- /dev/null +++ b/algorithm/2021F/lab_05/cs217.submit.csv @@ -0,0 +1,9 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 27, 36, 1, 17, 8, 89, 1, 42, 46 +B, 41, 23, 6, 1, 5, 1, 77, 41, 36 +C, 37, 3, 1, 4, 3, 48, 25, 23 +D, 30, 43, 3, 1, 3, 80, 1, 34, 45 +E, 46, 27, 18, 16, 34, 12, 153, 1, 71, 81 +F, 34, 27, 34, 5, 10, 9, 119, 2, 71, 46 +G, 42, 50, 44, 2, 10, 3, 151, 92, 59 +Total, 257, 209, 106, 24, 1, 81, 39, 717, 5, 376, 336 diff --git a/algorithm/2021F/lab_05/lab_05_A/CMakeLists.txt b/algorithm/2021F/lab_05/lab_05_A/CMakeLists.txt index 354751e1..40897f09 100644 --- a/algorithm/2021F/lab_05/lab_05_A/CMakeLists.txt +++ b/algorithm/2021F/lab_05/lab_05_A/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_05/lab_05_A/README.md b/algorithm/2021F/lab_05/lab_05_A/README.md new file mode 100644 index 00000000..79674a5a --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_A/README.md @@ -0,0 +1,106 @@ +# lab_05_A — Canteen Queue + +## Description + +It's lunch time now! + +Students are queuing in a queue and each student has one specific kind of favourite food + +The canteen offers different kinds of food in a stack + +If the food on the top of the stack matches one's favourite food in his turn, he will take it and leave the queue. + +Otherwise, he will go back to the end of the line to queue up again. + +The canteen will open for $T$ time slots. + +LowbieH now gives you the event of each time slot. + +There are 3 types of events in total: + ++ Event 1 : NewFood NameOfNewFood (Push new food into the stack.) ++ Event 2 : NewComer NameOfFavouriteFood (A new student will join the queue with his favourite food.) ++ Event 3 : TakeFood (The first student in the queue will make his choice. If the food stack is empty, he will do nothing. ) + +After $T$ time slots, the canteen will stop providing new food. The remaining students in the queue will take the food or queue again successively until the food stack is empty or nobody could get his favourite food . After that the canteen will close. Can you tell LowbieH that how many students will be left to starve when the canteen closes? + +## Input + +The first line contains an integer $T(0 \leq T \leq 10000)$. The following $T$ lines are the events that mentioned in the description above. The input is guaranteed to be valid. + +## Output + +If everyone had taken his favorite food, you should print "Qi Fei!"(without quotation marks). Otherwise, please tell LowbieH the number of the remaining hungry students. + +## Sample Input + +```log +6 +NewComer SpicyHotPot +NewComer BarbecuedPorkCombo +NewFood BarbecuedPorkCombo +TakeFood +NewFood SpicyHotPot +NewFood BarbecuedPorkCombo +``` + +## Sample Output + +```log +Qi Fei! +``` + +## 解题思路 + +### 问题分析 + +本题模拟了一个食堂打饭的场景, 涉及两种数据结构: +1. **学生队列 (Queue)**: 学生排队, 符合先进先出 (FIFO) 的特性. +2. **食物栈 (Stack)**: 食堂提供的食物, 符合后进先出 (LIFO) 的特性. + +核心逻辑是: ++ 队首的学生查看栈顶的食物. ++ 如果食物是该学生喜欢的, 学生取走食物并离开队列. ++ 如果不是, 学生回到队尾重新排队. ++ 这个过程会持续进行, 直到食物栈为空, 或者队列中的所有学生都无法在当前栈顶找到自己喜欢的食物. + +### 数据结构选择 + +根据题目描述, `main.cpp` 的实现直接使用了 C++ STL 中对应的标准容器: ++ `std::queue comer`: 用于模拟学生队列. ++ `std::stack way`: 用于模拟食物栈. + +为了处理食物名称这种字符串类型, 代码采用 `std::hash` 将字符串转换为 `size_t` 类型的哈希值进行存储和比较. 这样做可以提高比较效率, 避免了在循环中进行大量的字符串比较. + +### 算法流程 + +1. **初始化**: + + 读取事件数量 `T`. + + 创建 `stack way` 和 `queue comer`. + + 使用 `std::hash` 预计算 "NewFood", "NewComer", "TakeFood" 等命令的哈希值, 以便快速匹配命令. + +2. **处理 T 个时间槽的事件**: + + 循环 `T` 次, 每次读取一个事件. + + **NewFood**: 将新食物的名称哈希后压入 `way` 栈. + + **NewComer**: 将新学生的喜爱食物名称哈希后加入 `comer` 队列. + + **TakeFood**: + + 检查食物栈 `way` 是否为空. 如果为空, 则什么都不做. + + 如果食物栈不为空, 取出队首学生 `comer.front()` 和栈顶食物 `way.top()`. + + 比较两者. 如果匹配, 则学生出队, 食物出栈. + + 如果不匹配, 学生出队后, 再重新入队, 回到队尾. + +3. **处理剩余学生**: + + 在 `T` 个时间槽结束后, 进入一个 `while` 循环, 处理仍在队列中的学生. + + 这个循环的终止条件是: 食物栈 `way` 为空, 或者学生队列 `comer` 为空. + + 还有一个重要的终止条件: **死锁检测**. 如果队列中的所有学生都轮了一遍, 却没有一个人能取走食物, 那么就不会再有变化了, 循环必须终止. + + 代码通过一个计数器 `continue_time` 来实现死锁检测. `continue_time` 记录了连续多少个学生无法取走食物. 如果 `continue_time` 等于当前队列的长度 `comer_size`, 就意味着发生了死锁, 循环中断. + + 如果一个学生成功取走食物, `continue_time` 会被重置为 0. + +4. **输出结果**: + + 统计总学生数和成功取走食物的学生数. + + 如果两者相等, 说明所有学生都吃到了饭, 输出 "Qi Fei!". + + 否则, 输出两者之差, 即挨饿的学生数量. + +### 结论 + +该实现清晰地模拟了题目所描述的整个过程. 通过使用标准库中的 `queue` 和 `stack`, 代码结构简单明了. 关键点在于第二阶段处理剩余学生时的 **死锁判断**, 这是确保程序在无解情况下能够正常终止的核心. diff --git a/algorithm/2021F/lab_05/lab_05_A/lab_05_A.cpp b/algorithm/2021F/lab_05/lab_05_A/main.cpp similarity index 69% rename from algorithm/2021F/lab_05/lab_05_A/lab_05_A.cpp rename to algorithm/2021F/lab_05/lab_05_A/main.cpp index a8b73128..d601424e 100644 --- a/algorithm/2021F/lab_05/lab_05_A/lab_05_A.cpp +++ b/algorithm/2021F/lab_05/lab_05_A/main.cpp @@ -1,48 +1,5 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: 2020-2025 nanoseeds -/* - * @题目描述 - * 惧亡者排成一个队列,每个惧亡者都有一个生体转化偏好 - * 星神在一个栈中提供各种生体转化可能性 - * 如果栈顶的生体转化匹配上了惧亡者的生体转化偏好,该惧亡者将被生体转化为 太空死灵, 并从队列中移除 - * 否则,该惧亡者将重新进入队列尾部 - * - * 每个时隙内,会有不同事件发生 - * 第一种: `NewFold ${NAME_OF_NEW_FOOD}` 生体转化堆中推入新可能性 - * 第二种: `NewComer ${NAME_OF_FAVORITE_FOOD}` 新的惧亡者进入队列 - * 第三种: `TakeFood` 队列首部惧亡者进行选择,若生体转化堆为空,则等待 - * 所有时隙后,星神不再提供新的生体转化可能性 - * - * 剩余的惧亡者将进行生体转化 直到 生体转化堆 为空 或者没有惧亡者能够进行生体转化 - * 此时星神将会结束生体转化. - * - * 输出生体转化结束时多少惧亡者 还没有进行生体转化 - *@输入 - * 第一行数字 α,代表时隙数量 [0,1000] - * 之后是 α行操作 - *@输出 - * 若全部都进行了,则输出 R"(Qi Fei!)" - * 否则,输出数字 - *@样例 - * @输入 - * 6 - * NewComer SpicyHotPot - * NewComer BarbecuedPorkCombo - * NewFood BarbecuedPorkCombo - * TakeFood - * NewFood SpicyHotPot - * NewFood BarbecuedPorkCombo - * @输出 - * Qi Fei! - * */ -//@Tag DONE - -#ifndef ALGORITHM_TEST_MACRO -#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") -#pragma GCC optimize("inline-small-functions") -#pragma GCC optimize("-finline-small-functions") -#pragma GCC target("mmx") -#endif #include #include @@ -51,7 +8,12 @@ #include #include -#ifdef ALGORITHM_TEST_MACRO +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else namespace lab_05_A{ #endif diff --git a/algorithm/2021F/lab_05/lab_05_A/lab_05_A_test.cpp b/algorithm/2021F/lab_05/lab_05_A/test.cpp similarity index 98% rename from algorithm/2021F/lab_05/lab_05_A/lab_05_A_test.cpp rename to algorithm/2021F/lab_05/lab_05_A/test.cpp index 82fff60a..8256b075 100644 --- a/algorithm/2021F/lab_05/lab_05_A/lab_05_A_test.cpp +++ b/algorithm/2021F/lab_05/lab_05_A/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_05_A.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_05/lab_05_A/resource/"; } diff --git a/algorithm/2021F/lab_05/lab_05_B/CMakeLists.txt b/algorithm/2021F/lab_05/lab_05_B/CMakeLists.txt index c490830a..dac0839a 100644 --- a/algorithm/2021F/lab_05/lab_05_B/CMakeLists.txt +++ b/algorithm/2021F/lab_05/lab_05_B/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_05/lab_05_B/README.md b/algorithm/2021F/lab_05/lab_05_B/README.md new file mode 100644 index 00000000..0afeeb7a --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_B/README.md @@ -0,0 +1,52 @@ + +# lab_05_B — Two Queues Ticket Office + +## Description + +SUSTech Cinema is open for business! + +There are two ticket offices and all the students form two queues. + +It takes each student one minute to buy his ticket(s). + +The students can be separated into `n` groups each with one or two people. + +To save time, two students in the same group will not queue up in the same line. + +For the two-students group, if one group member has bought the tickets, the other one will leave the queue immediately. + +Also, if two students get to the ticket windows at the same time, then they will buy their own ticket respectively. + +Now LowbieH will give the description of the queueing situation, can you tell him the waiting time for each group? + +## Input + +The first line contains three integers `n, p, q (1 ≤ p, q ≤ n ≤ 100000)`, which are the number of groups and the lengths of the two queues. + +The following two lines consist of serial numbers (range from `1` to `n`) in each queue separately. + +Two same serial numbers stand for a two-people group. + +## Output + +Output the waiting time of each group in order. + +## Sample Input + +```log +5 4 5 +1 2 3 4 +2 4 1 3 5 +``` + +## Sample Output + +```log +1 1 2 2 3 +``` + +## Idea + +Simulate the process minute by minute: maintain two queues (arrays) storing group ids and process each minute by decrementing remaining people in front if present; record completion time per group. + +Use arrays to track whether a group's member already bought the ticket so the other member leaves upon arrival. diff --git a/algorithm/2021F/lab_05/lab_05_B/lab_05_B.cpp b/algorithm/2021F/lab_05/lab_05_B/main.cpp similarity index 98% rename from algorithm/2021F/lab_05/lab_05_B/lab_05_B.cpp rename to algorithm/2021F/lab_05/lab_05_B/main.cpp index 6dadf006..0e612b7a 100644 --- a/algorithm/2021F/lab_05/lab_05_B/lab_05_B.cpp +++ b/algorithm/2021F/lab_05/lab_05_B/main.cpp @@ -6,13 +6,6 @@ * */ //@Tag DONE -#ifndef ALGORITHM_TEST_MACRO -#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") -#pragma GCC optimize("inline-small-functions") -#pragma GCC optimize("-finline-small-functions") -#pragma GCC target("mmx") -#endif - #include #include #include @@ -20,7 +13,12 @@ #include #include -#ifdef ALGORITHM_TEST_MACRO +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else namespace lab_05_B{ #endif diff --git a/algorithm/2021F/lab_05/lab_05_B/lab_05_B_test.cpp b/algorithm/2021F/lab_05/lab_05_B/test.cpp similarity index 98% rename from algorithm/2021F/lab_05/lab_05_B/lab_05_B_test.cpp rename to algorithm/2021F/lab_05/lab_05_B/test.cpp index 49ace72f..a14727b2 100644 --- a/algorithm/2021F/lab_05/lab_05_B/lab_05_B_test.cpp +++ b/algorithm/2021F/lab_05/lab_05_B/test.cpp @@ -8,14 +8,13 @@ #include #include -#include "lab_05_B.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_05/lab_05_B/resource/"; } const std::string CS203_redirect::file_paths = getFilePath(); namespace lab_05_B { - using std::tie; using std::cin; using std::cout; diff --git a/algorithm/2021F/lab_05/lab_05_C/CMakeLists.txt b/algorithm/2021F/lab_05/lab_05_C/CMakeLists.txt index 5de3f24f..f07d2e4c 100644 --- a/algorithm/2021F/lab_05/lab_05_C/CMakeLists.txt +++ b/algorithm/2021F/lab_05/lab_05_C/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_05/lab_05_C/README.md b/algorithm/2021F/lab_05/lab_05_C/README.md new file mode 100644 index 00000000..d1f9b505 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_C/README.md @@ -0,0 +1,61 @@ +# lab_05_C — Bracket Matching + +## Description + +LowbieH is learning about matching brackets in the classroom. + +There are n brackets, and LowbieH wants to know whether they are matched. + +The brackets will only contain `{, }, (, ), [, ]`. + +Here is the matching rules. + +For example, `{(}{[]})` is not matched, but `([{{}}()])` is matched. + +Please write a program to check whether the given string is matched or not. + +## Input + +The first line will be an integer `T (1 <= T <= 10)`, which is the number of test cases. + +For each test case, the first line will be an integer `n(1 <= n <= 30000)`. + +Then there is a line with `n` brackets. + +## Output + +For each test case, print YES if the test case is a matched case. + +Otherwise, print NO. + +## Sample Input + +```log +7 +1 +( +2 +() +2 +{] +6 +[(){}] +4 +(])[ +8 +[[{{}}]] +6 +][{]] +``` + +## Sample Output + +```log +NO +YES +NO +YES +NO +YES +NO +``` diff --git a/algorithm/2021F/lab_05/lab_05_C/lab_05_C.cpp b/algorithm/2021F/lab_05/lab_05_C/main.cpp similarity index 97% rename from algorithm/2021F/lab_05/lab_05_C/lab_05_C.cpp rename to algorithm/2021F/lab_05/lab_05_C/main.cpp index 5e35f038..2fa57c65 100644 --- a/algorithm/2021F/lab_05/lab_05_C/lab_05_C.cpp +++ b/algorithm/2021F/lab_05/lab_05_C/main.cpp @@ -6,12 +6,6 @@ * */ //@Tag DONE -#ifndef ALGORITHM_TEST_MACRO -#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") -#pragma GCC optimize("inline-small-functions") -#pragma GCC optimize("-finline-small-functions") -#pragma GCC target("mmx") -#endif #include #include @@ -22,7 +16,12 @@ #include #include -#ifdef ALGORITHM_TEST_MACRO +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else namespace lab_05_C{ #endif diff --git a/algorithm/2021F/lab_05/lab_05_C/lab_05_C_test.cpp b/algorithm/2021F/lab_05/lab_05_C/test.cpp similarity index 98% rename from algorithm/2021F/lab_05/lab_05_C/lab_05_C_test.cpp rename to algorithm/2021F/lab_05/lab_05_C/test.cpp index d995f90a..fcbbf5bf 100644 --- a/algorithm/2021F/lab_05/lab_05_C/lab_05_C_test.cpp +++ b/algorithm/2021F/lab_05/lab_05_C/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_05_C.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_05/lab_05_C/resource/";} diff --git a/algorithm/2021F/lab_05/lab_05_D/CMakeLists.txt b/algorithm/2021F/lab_05/lab_05_D/CMakeLists.txt index dce330ce..564aeae5 100644 --- a/algorithm/2021F/lab_05/lab_05_D/CMakeLists.txt +++ b/algorithm/2021F/lab_05/lab_05_D/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_05/lab_05_D/README.md b/algorithm/2021F/lab_05/lab_05_D/README.md new file mode 100644 index 00000000..e280af17 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_D/README.md @@ -0,0 +1,42 @@ +# lab_05_D — Parentheses Scoring + +## Description + +LowbieH and Peggy are in the playroom to figure out an interesting problem. + +Given a string of matched parenthesis `s`, the scoring rules are defined by: +1. If `s=()`, then `score(s)=1`. +2. If `t` is another string of matched parenthesis, then `score(s+t)=score(s)+score(t)`. +3. `score((s)) = score(s)*2`. + +LowbieH and Peggy want to calculate the score of given string quickly, can you help them? + +Since the answer may be very large, you only need to tell them the score after mod `514329`. + +## Input + +One line a string. + +It contains only parenthesis and is perfect matched. + +The length of input will not exceed `100000`. + +## Output + +One line an integer, denoting the score ( mod `514329`). + +## Sample Input + +```log +((()())()) +``` + +## Sample Output + +```log +10 +``` + +## HINT + +`score(((()())())) = ((1 + 1) * 2 + 1) * 2 = 10` diff --git a/algorithm/2021F/lab_05/lab_05_D/lab_05_D.cpp b/algorithm/2021F/lab_05/lab_05_D/main.cpp similarity index 97% rename from algorithm/2021F/lab_05/lab_05_D/lab_05_D.cpp rename to algorithm/2021F/lab_05/lab_05_D/main.cpp index f06e9626..df50420e 100644 --- a/algorithm/2021F/lab_05/lab_05_D/lab_05_D.cpp +++ b/algorithm/2021F/lab_05/lab_05_D/main.cpp @@ -5,13 +5,6 @@ * */ //@Tag DONE -#ifndef ALGORITHM_TEST_MACRO -#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") -#pragma GCC optimize("inline-small-functions") -#pragma GCC optimize("-finline-small-functions") -#pragma GCC target("mmx") -#endif - #include #include #include @@ -19,7 +12,12 @@ #include #include -#ifdef ALGORITHM_TEST_MACRO +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else namespace lab_05_D{ #endif diff --git a/algorithm/2021F/lab_05/lab_05_D/lab_05_D_test.cpp b/algorithm/2021F/lab_05/lab_05_D/test.cpp similarity index 98% rename from algorithm/2021F/lab_05/lab_05_D/lab_05_D_test.cpp rename to algorithm/2021F/lab_05/lab_05_D/test.cpp index 9958bb16..49708441 100644 --- a/algorithm/2021F/lab_05/lab_05_D/lab_05_D_test.cpp +++ b/algorithm/2021F/lab_05/lab_05_D/test.cpp @@ -8,14 +8,13 @@ #include #include -#include "lab_05_D.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_05/lab_05_D/resource/"; } const std::string CS203_redirect::file_paths = getFilePath(); namespace lab_05_D { - using std::tie; using std::cin; using std::cout; diff --git a/algorithm/2021F/lab_05/lab_05_E/CMakeLists.txt b/algorithm/2021F/lab_05/lab_05_E/CMakeLists.txt new file mode 100644 index 00000000..f6252ecc --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER E) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_05/lab_05_E/README.md b/algorithm/2021F/lab_05/lab_05_E/README.md new file mode 100644 index 00000000..f89265b1 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/README.md @@ -0,0 +1,102 @@ +# lab_05_E — Deque Operations + +## Description + +In the library, LowbieH is learning the double-ended queue, which is also called deque. + +He thinks that it is very interesting and invites you to join him. + +Now there are `n` empty deques numbered from `1` to `n`, you need to implement three types of operations that LowbieH asks you. + +Type-1: `1 u w val`. Insert `val` to the deque numbered by `u`. (`w=0` means that the insertion is done in the front, `w=1` means that the insertion is done in the rear) + +Type-2: `2 u w`. Query the front or the rear element in the deque numbered by `u` and pop it out. (`w=0` means the front, `w=1` means the rear) + +Type-3: `3 u v w`. Connect the deque numbered by `v` to the rear of the deque numbered by `u(u != v)`. (`w=0` means a direct connection, `w=1` means a reversed connection, that is to say you need to first reverse the deque numbered by `v` and then connect them) + +The deque numbered by `v` will be cleared after the connection. + +### Input + +Multiple test cases . + +Please process to the end of file . + +For each test case, the first line contains two integers `n(1<= n <= 10^5)` and `q(1<= q <= 10^5)`, denoting the number of the deques and the number of the operations. + +The following `q` lines will be the three types of operations that have been explained. + +`1<= u,v <= n`, `0<= w <= 1`, `1<= val <= 10^5`. + +It is guaranteed that the total number of operations will not exceed `3*10^5`. + +### Output + +Print one line an integer denoting the answer for each type-2 operation. + +If the deque is empty, then print `-1` instead. + +### Sample Input + +```log +2 10 +1 1 1 23 +1 1 0 233 +2 1 1 +1 2 1 2333 +1 2 1 23333 +3 1 2 1 +2 2 0 +2 1 1 +2 1 0 +2 1 1 +2 10 +1 1 1 23 +1 1 0 233 +2 1 1 +1 2 1 2333 +1 2 1 23333 +3 1 2 1 +2 2 0 +2 1 1 +2 1 0 +2 1 1 +``` + +### Sample Output + +```log +23 +-1 +2333 +233 +23333 +23 +-1 +2333 +233 +23333 +``` + +## HINT + +The data is randomly generated , so you can assume that the expected length of each deque is very small. + +You are encouraged to self-study the implementation of deque + +## 复用信息 + ++ Contest 1083:2020 Fall Lab05 Stack + Queue ++ Contest 1168:CS203 2024 Fall Lab 4 ++ Contest 1099:CS203 2021 Fall Lab 05 Stack + Queue ++ Contest 1100:CS217 2021 Fall Lab 05 Stack + Queue + +## Algorithm Analysis (实现说明) + ++ 思路: 使用 n 个容器(deque)模拟每个编号的双端队列。对三种操作分别处理: + 1) 插入: 根据当前逻辑反转标志 rev[u] 决定 push_front/push_back 的物理方向。 + 2) 弹出并查询: 根据 rev[u] 与 w 决定从物理头或尾取出。 + 3) 连接: 为节省数据移动,选择把元素少的桶合并到元素多的桶,或把两个桶的物理关系调整后重绑 bucket id。通过维护 bid[](每个编号指向现有桶 id)和 rev[](逻辑反转标志)实现 O(min(|A|,|B|)) 的合并。 ++ 实现要点: 使用 `vector>` 存储物理容器,`bid[u]` 跟踪 u 当前指向的物理容器索引;`rev[u]` 标记逻辑是否反转。合并时按大小选择移动方向以降低总移动次数。 ++ 复杂度: 每个元素在合并过程中被移动 O(log n) 次均摊(更常见的分析是每个元素移动次数等于被合并进更大的桶的次数),总体在操作数限制下可接受。单次插入/弹出 O(1)。 ++ 边界: 当 u==v 或被合并桶为空时要跳过操作;输入可能包含多组测试用例,程序需要读取到 EOF。 diff --git a/algorithm/2021F/lab_05/lab_05_E/main.cpp b/algorithm/2021F/lab_05/lab_05_E/main.cpp new file mode 100644 index 00000000..68920ef4 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/main.cpp @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_05_E { +#endif +using std::cin; +using std::cout; +using std::deque; +using std::tie; +using std::tuple; +using std::vector; +using num_t = int32_t; + +// Operation and test case definitions for structured input +struct Operation { + int op, u, w, v, val; +}; + +struct TestCase { + int n, q; + vector ops; +}; + +using input_type = vector; +using output_type = vector; + +static constexpr const char end{'\n'}; + +inline input_type read(); + +// Process test cases and collect outputs +output_type cal(const input_type &tests); + +void output(const output_type &data); + +int main() { + const auto input_data = read(); + const auto output_data = cal(input_data); + output(output_data); + return 0; +} + +// Read all test cases and operations +inline input_type read() { + input_type tests; + int n, q; + while (cin >> n >> q) { + TestCase tc{n, q, {}}; + tc.ops.reserve(q); + for (int i = 0; i < q; ++i) { + Operation o{}; + cin >> o.op; + if (o.op == 1) { + cin >> o.u >> o.w >> o.val; + } else if (o.op == 2) { + cin >> o.u >> o.w; + } else if (o.op == 3) { + cin >> o.u >> o.v >> o.w; + } + tc.ops.push_back(o); + } + tests.push_back(std::move(tc)); + } + return tests; +} + +// Output all collected results +void output(const output_type &data) { + for (num_t v: data) cout << v << end; +} + +// Process test cases and collect outputs +output_type cal(const input_type &tests) { + output_type results; + for (const auto &tc: tests) { + int n = tc.n; + vector > buckets(n + 1); + vector bid(n + 1); + vector rev(n + 1, 0); + for (int i = 1; i <= n; ++i) bid[i] = i; + for (const auto &o: tc.ops) { + if (o.op == 1) { + int u = o.u, w = o.w, val = o.val; + int b = bid[u]; + if (w == 0) { + if (!rev[u]) buckets[b].push_front(val); + else buckets[b].push_back(val); + } else { + if (!rev[u]) buckets[b].push_back(val); + else buckets[b].push_front(val); + } + } else if (o.op == 2) { + int u = o.u, w = o.w; + int b = bid[u]; + if (buckets[b].empty()) { + results.push_back(-1); + } else { + int ans; + if (w == 0) { + if (!rev[u]) { + ans = buckets[b].front(); + buckets[b].pop_front(); + } else { + ans = buckets[b].back(); + buckets[b].pop_back(); + } + } else { + if (!rev[u]) { + ans = buckets[b].back(); + buckets[b].pop_back(); + } else { + ans = buckets[b].front(); + buckets[b].pop_front(); + } + } + results.push_back(ans); + } + } else if (o.op == 3) { + int u = o.u, v = o.v, w = o.w; + if (u == v) continue; + int bu = bid[u], bv = bid[v]; + if (buckets[bv].empty()) continue; + + // Choose target bucket to minimize moves + if ((int) buckets[bu].size() >= (int) buckets[bv].size()) { + // Append into u's bucket + const bool push_to_back = (rev[u] == 0); + const bool take_back_to_front = ((rev[v] ^ w) == 1); // true => take back->front + if (!take_back_to_front) { + while (!buckets[bv].empty()) { + int x = buckets[bv].front(); + buckets[bv].pop_front(); + if (push_to_back) + buckets[bu].push_back(x); + else + buckets[bu].push_front(x); + } + } else { + while (!buckets[bv].empty()) { + int x = buckets[bv].back(); + buckets[bv].pop_back(); + if (push_to_back) + buckets[bu].push_back(x); + else + buckets[bu].push_front(x); + } + } + // v becomes empty automatically + } else { + // Build into v's bucket, then reassign it to u + int new_rev_u = rev[v] ^ w; + if (new_rev_u == 0) { + // Physical P = U + current V; push U to front preserving U logical order + if (rev[u] == 0) { + while (!buckets[bu].empty()) { + int x = buckets[bu].back(); + buckets[bu].pop_back(); + buckets[bv].push_front(x); + } + } else { + while (!buckets[bu].empty()) { + int x = buckets[bu].front(); + buckets[bu].pop_front(); + buckets[bv].push_front(x); + } + } + } else { + // new_rev_u == 1: Physical P = current V + reverse(U); push reverse(U) to back + if (rev[u] == 0) { + while (!buckets[bu].empty()) { + int x = buckets[bu].back(); + buckets[bu].pop_back(); + buckets[bv].push_back(x); + } + } else { + while (!buckets[bu].empty()) { + int x = buckets[bu].front(); + buckets[bu].pop_front(); + buckets[bv].push_back(x); + } + } + } + // Reassign buckets + bid[u] = bv; + bid[v] = bu; // now empty + rev[u] = new_rev_u; + } + } + } + } + return results; +} + + +static const auto faster_streams = [] { + srand(time(nullptr)); + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_05/lab_05_E/resource/1.data.in b/algorithm/2021F/lab_05/lab_05_E/resource/1.data.in new file mode 100644 index 00000000..56c9bbae --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/resource/1.data.in @@ -0,0 +1,22 @@ +2 10 +1 1 1 23 +1 1 0 233 +2 1 1 +1 2 1 2333 +1 2 1 23333 +3 1 2 1 +2 2 0 +2 1 1 +2 1 0 +2 1 1 +2 10 +1 1 1 23 +1 1 0 233 +2 1 1 +1 2 1 2333 +1 2 1 23333 +3 1 2 1 +2 2 0 +2 1 1 +2 1 0 +2 1 1 diff --git a/algorithm/2021F/lab_05/lab_05_E/resource/1.data.out b/algorithm/2021F/lab_05/lab_05_E/resource/1.data.out new file mode 100644 index 00000000..a0333735 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/resource/1.data.out @@ -0,0 +1,10 @@ +23 +-1 +2333 +233 +23333 +23 +-1 +2333 +233 +23333 diff --git a/algorithm/2021F/lab_05/lab_05_E/resource/2.data.in b/algorithm/2021F/lab_05/lab_05_E/resource/2.data.in new file mode 100644 index 00000000..aa001bdc --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/resource/2.data.in @@ -0,0 +1,17 @@ +3 9 +1 1 1 10 +1 1 0 20 +1 2 1 30 +3 1 2 0 +2 1 0 +2 1 1 +2 2 0 +1 3 1 40 +2 1 1 +2 6 +1 1 1 1 +1 2 1 2 +3 1 2 1 +2 1 0 +2 1 1 +2 2 0 diff --git a/algorithm/2021F/lab_05/lab_05_E/resource/2.data.out b/algorithm/2021F/lab_05/lab_05_E/resource/2.data.out new file mode 100644 index 00000000..dccad012 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/resource/2.data.out @@ -0,0 +1,7 @@ +20 +30 +-1 +10 +1 +2 +-1 diff --git a/algorithm/2021F/lab_05/lab_05_E/resource/3.data.in b/algorithm/2021F/lab_05/lab_05_E/resource/3.data.in new file mode 100644 index 00000000..b4e0cec2 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/resource/3.data.in @@ -0,0 +1,12 @@ +5 11 +1 1 1 5 +1 1 1 6 +1 2 0 7 +1 3 1 8 +3 1 3 1 +3 1 2 1 +2 1 0 +2 1 0 +2 1 1 +3 4 1 0 +2 4 0 diff --git a/algorithm/2021F/lab_05/lab_05_E/resource/3.data.out b/algorithm/2021F/lab_05/lab_05_E/resource/3.data.out new file mode 100644 index 00000000..3aac70f8 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/resource/3.data.out @@ -0,0 +1,4 @@ +5 +6 +7 +8 diff --git a/algorithm/2021F/lab_05/lab_05_E/resource/4.data.in b/algorithm/2021F/lab_05/lab_05_E/resource/4.data.in new file mode 100644 index 00000000..ca5f1d4b --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/resource/4.data.in @@ -0,0 +1,21 @@ +4 12 +1 1 1 1 +1 1 1 2 +1 2 0 3 +3 1 2 1 +2 1 0 +2 1 1 +1 3 0 4 +3 1 3 0 +2 1 0 +2 1 1 +2 1 0 +2 4 0 + +2 6 +1 1 1 5 +1 2 1 6 +3 1 2 0 +2 1 0 +2 1 1 +2 2 0 diff --git a/algorithm/2021F/lab_05/lab_05_E/resource/4.data.out b/algorithm/2021F/lab_05/lab_05_E/resource/4.data.out new file mode 100644 index 00000000..56423cee --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/resource/4.data.out @@ -0,0 +1,9 @@ +1 +3 +2 +4 +-1 +-1 +5 +6 +-1 diff --git a/algorithm/2021F/lab_05/lab_05_E/resource/5.data.in b/algorithm/2021F/lab_05/lab_05_E/resource/5.data.in new file mode 100644 index 00000000..8afd24cb --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/resource/5.data.in @@ -0,0 +1,18 @@ +6 15 +1 1 1 10 +1 2 1 20 +1 3 1 30 +3 1 2 0 +3 1 3 1 +1 4 0 40 +1 4 0 41 +3 1 4 0 +2 1 1 +2 1 0 +1 5 1 50 +3 1 5 1 +2 1 0 +2 1 1 +3 6 1 0 +2 6 0 +2 1 0 diff --git a/algorithm/2021F/lab_05/lab_05_E/resource/5.data.out b/algorithm/2021F/lab_05/lab_05_E/resource/5.data.out new file mode 100644 index 00000000..fe078779 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/resource/5.data.out @@ -0,0 +1,5 @@ +40 +10 +20 +50 +-1 diff --git a/algorithm/2021F/lab_05/lab_05_E/test.cpp b/algorithm/2021F/lab_05/lab_05_E/test.cpp new file mode 100644 index 00000000..3c151a13 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_E/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_05/lab_05_E/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_05_E { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 05_E]", "[test 05_E]") { + CS203_sequence sequence{1, 5, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_05/lab_05_F/CMakeLists.txt b/algorithm/2021F/lab_05/lab_05_F/CMakeLists.txt new file mode 100644 index 00000000..3bd8bb2b --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_F/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER F) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_05/lab_05_F/README.md b/algorithm/2021F/lab_05/lab_05_F/README.md new file mode 100644 index 00000000..c6961990 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_F/README.md @@ -0,0 +1,73 @@ +# lab_05_F — Longest Subarray with Bounded Difference + +## Description + +Dateri has a magic sequence and LowbieH is interested in it. + +Dateri promises that if LowbieH can answer his question, then he will play fencing with LowbieH . + +We denote the magic sequence by `{a_n}` and Dateri will choose a lucky number `k`. + +He asks LowbieH to find length of the longest consecutive subsequence such that the absolute difference between any two number in the subsequence should not exceed `k`. + +Can you help LowbieH? + +## Input + +The first line contains two integers `k(0 <= k <= 2*10^9)` and `n(1 <= n <= 3 * 10^6)`. + +The second line contains `n` integers `a_1,...,a_n(1 <= a_i <= 2 * 10^9, 1 <= i <= n)`. + +## Output + +One line contains the answer, i.e. the length of the longest available consecutive subsequence. + +## Sample Input + +```log +3 9 +5 1 3 5 8 6 6 9 10 +``` + +## Sample Output + +```log +4 +``` + +## HINT + +There are two available consecutive subsequences : `{5,8,6,6}` and `{8,6,6,9}`. + +## 复用信息 + ++ Contest 1083:2020 Fall Lab05 Stack + Queue ++ Contest 1099:CS203 2021 Fall Lab 05 Stack + Queue ++ Contest 1100:CS217 2021 Fall Lab 05 Stack + Queue ++ Contest 1143:CS203 2023 Fall Lab 4 Stack/Queue ++ Contest 1168:CS203 2024 Fall Lab 4 + +## Analysis + +思路: 维护一个滑动窗口, 在窗口内需要同时知道最大值与最小值, 若二者差值不超过 k 则窗口合法. + +为了 O(1) 均摊获取窗口最大最小, 使用两个单调队列(deque): + +1. q_max: 保存可能成为最大值的下标, 对应值严格递增弹出尾部保持递减队列. +2. q_min: 保存可能成为最小值的下标, 对应值严格递减弹出尾部保持递增队列. + +右指针每前进一位, 将元素更新进入两个队列; 若当前窗口内最大值与最小值之差大于 k, 左指针收缩, 同时弹出已经离开窗口的下标. + +窗口收缩直至满足条件, 此时统计窗口长度更新答案. + +时间复杂度: 每个元素进出每个双端队列至多一次, O(n). + +空间复杂度: 两个双端队列 O(n) 最坏, 均摊近似 O(1) 额外. + +边界情况: + +1. n=1 时答案为 1. +2. k=0 时寻找最长相同元素的连续段. +3. 全部单调递增且差值逐渐超过 k 时需正确收缩. +4. 数据范围大 (2*10^9) 但只做差值比较, 使用 64 位中间计算避免潜在溢出. + diff --git a/algorithm/2021F/lab_05/lab_05_F/main.cpp b/algorithm/2021F/lab_05/lab_05_F/main.cpp new file mode 100644 index 00000000..d18cd5d6 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_F/main.cpp @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_05_F{ +#endif +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +static constexpr const char end{'\n'}; + +using num_t = int32_t; // 数值和长度均在int32范围内 +using input_type = tuple>; // k, n, sequence +using output_type = num_t; // 最长长度 + +inline input_type read(); +output_type cal(const input_type &data); +void output(const output_type &data); + +int main() { + const auto input_data = read(); + const auto output_data = cal(input_data); + output(output_data); + return 0; +} + +inline input_type read() { + // 输入: k n 然后 n 个数 + num_t k{0}, n{0}; + cin >> k >> n; + std::vector arr; + arr.resize(static_cast(n)); + for (num_t i = 0; i < n; ++i) { + cin >> arr[static_cast(i)]; + } + return std::make_tuple(k, n, std::move(arr)); +} + +output_type cal(const input_type &data) { + // 计算满足 max - min <= k 的最长连续子数组长度 + const num_t k = std::get<0>(data); + const num_t n = std::get<1>(data); + const auto &a = std::get<2>(data); + if (n == 0) { return 0; } + + std::deque q_max; // 存储下标, 保持对应值严格递减 + std::deque q_min; // 存储下标, 保持对应值严格递增 + + num_t best = 1; // 至少为1 + num_t left = 0; // 当前窗口左端 + for (num_t right = 0; right < n; ++right) { + const auto val = a[static_cast(right)]; + // 维护最大值队列: 去掉 <= 当前值的尾部元素 + while (!q_max.empty() && a[static_cast(q_max.back())] <= val) { + q_max.pop_back(); + } + q_max.push_back(right); + // 维护最小值队列: 去掉 >= 当前值的尾部元素 + while (!q_min.empty() && a[static_cast(q_min.back())] >= val) { + q_min.pop_back(); + } + q_min.push_back(right); + + // 若当前窗口不满足条件, 缩小左端 + while (!q_max.empty() && !q_min.empty() && (static_cast(a[static_cast(q_max.front())]) - static_cast(a[static_cast(q_min.front())]) > k)) { + // 向右移动左端 + ++left; + // 弹出已经不在窗口内的下标 + if (!q_max.empty() && q_max.front() < left) { q_max.pop_front(); } + if (!q_min.empty() && q_min.front() < left) { q_min.pop_front(); } + } + // 更新答案 (窗口为 [left, right]) + const num_t cur_len = right - left + 1; + if (cur_len > best) { best = cur_len; } + } + return best; +} + +void output(const output_type &data) { cout << data << end; } + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_05/lab_05_F/resource/1.data.in b/algorithm/2021F/lab_05/lab_05_F/resource/1.data.in new file mode 100644 index 00000000..2bcd803e --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_F/resource/1.data.in @@ -0,0 +1,2 @@ +3 9 +5 1 3 5 8 6 6 9 10 diff --git a/algorithm/2021F/lab_05/lab_05_F/resource/1.data.out b/algorithm/2021F/lab_05/lab_05_F/resource/1.data.out new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_F/resource/1.data.out @@ -0,0 +1 @@ +4 diff --git a/algorithm/2021F/lab_05/lab_05_F/test.cpp b/algorithm/2021F/lab_05/lab_05_F/test.cpp new file mode 100644 index 00000000..e181f28d --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_F/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_05/lab_05_F/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_05_F { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 05_F]", "[test 05_F]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_05/lab_05_G/CMakeLists.txt b/algorithm/2021F/lab_05/lab_05_G/CMakeLists.txt new file mode 100644 index 00000000..768dc1e2 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_G/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER G) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_05/lab_05_G/README.md b/algorithm/2021F/lab_05/lab_05_G/README.md new file mode 100644 index 00000000..7500f5a4 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_G/README.md @@ -0,0 +1,73 @@ +# lab_05_G — Mountain Pairs (Visible Pairs) + +## Description + +LowbieH and his friend wtd are on their trip to the SUSTech natural park. + +The place is quite mountainous and they can climb `n` mountains lying on a straight line numbered from `1` to `n`, each with height `h_i(1 <= i <= n)`. + +To save time, they decide to climb two different mountains and they want to see each other when they reach the top. + +That is to say, LowbieH will choose the `i_th` mountain and wtd will climb the `j_th` mountain`(1 <= i < j <= n)`. + +For the `k_th(i < k < j)` moutain that is between their choices, it should satisfy that `h_k < min(h_i, h_j)`. + +Thus no moutains will block cross their visions. + +Also, if LowbieH and wtd are on the adjacent mountains, they can certainly see each other. + +Now we define such pair of mountains `(i, j)` to be a happy pair if LowbieH and wtd can see each other on them. + +Can you tell them the number of all different happy pairs within given intervals ? + +## Input + +The first line of input contains two integers `n, q (1 <= n, q <= 3*10^5)`, which means the number of moutains and queries. + +The second line of input contains `n` integers `h_1, ..., h_n (1 <= h_i <= 10^9)`, denoting the height of each moutain. + +The following `q` lines contain two integers `l, r (1 <= l <= r <= n)` in each line, which means that the interval of query is `[l, r]`. + +You should calculate the number of different happy pairs within this interval. + +## Output + +The output will be `q` lines in total. + +Each line contains the answer of each query. + +## Sample Input + +```log +3 2 +2 1 2 +1 1 +1 3 +``` + +## Sample Output + +```log +0 +3 +``` + +## HINT + +You are recommended to use fast I/O. + +## 复用信息 + ++ Contest 1083:2020 Fall Lab05 Stack + Queue ++ Contest 1100:CS217 2021 Fall Lab 05 Stack + Queue + +## Algorithm Analysis (实现说明) + +- 思路: 使用单调栈将山峰分组,构造所有满足“可见对”(u,v) 的边,其中 `u +#include +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_05_G{ +#endif + +using std::cin; +using std::cout; +using std::vector; +using std::pair; +using std::int64_t; +static constexpr const char end{'\n'}; + +struct Fenwick { + int n; + vector bit; + Fenwick(int n_=0) { init(n_); } + void init(int n_) { + n = n_; + bit.assign(n + 1, 0); + } + inline void add(int idx, int64_t delta) { + for (; idx <= n; idx += idx & -idx) bit[idx] += delta; + } + inline int64_t sum(int idx) const { + int64_t res = 0; + for (; idx > 0; idx -= idx & -idx) res += bit[idx]; + return res; + } + inline int64_t range_sum(int l, int r) const { + if (l > r) return 0; + return sum(r) - sum(l - 1); + } +}; + +struct Event { + int x; // threshold on v + int l, r; // u range + int id; // query id + int w; // +1 or -1 + bool operator<(const Event& other) const { + return x < other.x; + } +}; + +struct Group { + int h; + vector idxs; // positions with equal height (stack-top group) +}; + +struct Input { + int n, q; + vector h; + vector> queries; +}; + +Input read_input() { + Input in; + if (!(cin >> in.n >> in.q)) return in; + in.h.resize(in.n + 1); + for (int i = 1; i <= in.n; ++i) cin >> in.h[i]; + in.queries.resize(in.q); + for (int i = 0; i < in.q; ++i) { + cin >> in.queries[i].first >> in.queries[i].second; + } + return in; +} + +vector solve(const Input& in) { + // Build all visible pairs (u, v), u < v + vector> edges; + edges.reserve(2 * in.n); + vector st; + st.reserve(in.n); + + for (int i = 1; i <= in.n; ++i) { + while (!st.empty() && st.back().h < in.h[i]) { + const int u = st.back().idxs.back(); + edges.emplace_back(u, i); + st.pop_back(); + } + if (st.empty()) { + st.push_back(Group{in.h[i], vector{i}}); + } else if (st.back().h == in.h[i]) { + int u = st.back().idxs.back(); + edges.emplace_back(u, i); + st.back().idxs.push_back(i); + } else { // st.back().h > h[i] + int u = st.back().idxs.back(); + edges.emplace_back(u, i); + st.push_back(Group{in.h[i], vector{i}}); + } + } + + // Offline answer queries + std::sort(edges.begin(), edges.end(), + [](const pair& a, const pair& b){ return a.second < b.second; }); + + vector events; + events.reserve(2 * in.q); + vector ans(in.q, 0); + for (int id = 0; id < in.q; ++id) { + int l = in.queries[id].first; + int r = in.queries[id].second; + events.push_back(Event{r, l, r, id, +1}); + events.push_back(Event{l - 1, l, r, id, -1}); + } + std::sort(events.begin(), events.end()); + + Fenwick bit(in.n); + size_t epos = 0; + for (const auto& ev : events) { + while (epos < edges.size() && edges[epos].second <= ev.x) { + bit.add(edges[epos].first, 1); + ++epos; + } + ans[ev.id] += (int64_t)ev.w * bit.range_sum(ev.l, ev.r); + } + return ans; +} + +void print_output(const vector& ans) { + for (const auto& val : ans) { + cout << val << end; + } +} + +int main() { + auto input = read_input(); + if (input.n == 0) return 0; + auto ans = solve(input); + print_output(ans); + return 0; +} + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_05/lab_05_G/resource/1.data.in b/algorithm/2021F/lab_05/lab_05_G/resource/1.data.in new file mode 100644 index 00000000..ebc7c78c --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_G/resource/1.data.in @@ -0,0 +1,4 @@ +3 2 +2 1 2 +1 1 +1 3 diff --git a/algorithm/2021F/lab_05/lab_05_G/resource/1.data.out b/algorithm/2021F/lab_05/lab_05_G/resource/1.data.out new file mode 100644 index 00000000..12decc13 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_G/resource/1.data.out @@ -0,0 +1,2 @@ +0 +3 diff --git a/algorithm/2021F/lab_05/lab_05_G/test.cpp b/algorithm/2021F/lab_05/lab_05_G/test.cpp new file mode 100644 index 00000000..44b93548 --- /dev/null +++ b/algorithm/2021F/lab_05/lab_05_G/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_05/lab_05_G/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_05_G { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 05_G]", "[test 05_G]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_06/CMakeLists.txt b/algorithm/2021F/lab_06/CMakeLists.txt new file mode 100644 index 00000000..78996834 --- /dev/null +++ b/algorithm/2021F/lab_06/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROJECT_ORDER lab_06) +project(${PROJECT_NAME}_${PROJECT_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +set(dependencies A B C D E F G) +foreach (elementName IN LISTS dependencies) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${elementName}) +endforeach () +unset(dependencies) diff --git a/algorithm/2021F/lab_06/README.md b/algorithm/2021F/lab_06/README.md new file mode 100644 index 00000000..4ca58cb7 --- /dev/null +++ b/algorithm/2021F/lab_06/README.md @@ -0,0 +1,33 @@ +# Contest1101 - CS203 2021 Fall Lab 06 String + +> cid: 1102 + +Welcome to CS203 2021 Fall Lab 06! Enjoy this Lab! + +There are six problems for you to solve. + +Score: + ++ A: 10 ++ B: 15/10 ++ C: 15/10 ++ D: 20/15 ++ E: 20/15 ++ F: 20 ++ G: undefined/20 + +Reading the samples and hints carefully can help you understand the problem. + +## 题目列表 + +| Problem | problem id | +|--------:|-----------:| +| A | 1446 | +| B | 1447 | +| C | 1448 | +| D | 1449 | +| E | 1450 | +| F | 1452 | +| G | 1451 | + +B, F被复用 diff --git a/algorithm/2021F/lab_06/cs203.submit.csv b/algorithm/2021F/lab_06/cs203.submit.csv new file mode 100644 index 00000000..16c1f609 --- /dev/null +++ b/algorithm/2021F/lab_06/cs203.submit.csv @@ -0,0 +1,8 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 233, 114, 3, 8, 5, 10, 33, 406, 10, 81, 315 +B, 253, 2, 99, 152, 11, 26, 50, 593, 20, 113, 460 +C, 247, 7, 137, 304, 2, 9, 45, 42, 1, 794, 27, 205, 562 +D, 236, 246, 152, 7, 7, 36, 27, 711, 16, 101, 594 +E, 235, 277, 318, 28, 9, 46, 49, 962, 9, 234, 719 +F, 225, 407, 253, 2, 11, 76, 34, 1008, 14, 159, 835 +Total, 1429, 9, 1280, 1182, 58, 41, 239, 235, 1, 4474, 96, 893, 3485 diff --git a/algorithm/2021F/lab_06/cs217.submit.csv b/algorithm/2021F/lab_06/cs217.submit.csv new file mode 100644 index 00000000..a58e07af --- /dev/null +++ b/algorithm/2021F/lab_06/cs217.submit.csv @@ -0,0 +1,9 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 27, 5, 1, 4, 37, 1, 20, 16 +B, 32, 8, 7, 4, 5, 56, 1, 31, 24 +C, 38, 1, 8, 31, 8, 4, 90, 1, 48, 41 +D, 38, 20, 6, 8, 1, 73, 49, 24 +E, 30, 31, 23, 4, 9, 5, 102, 42, 60 +F, 28, 16, 6, 1, 9, 6, 66, 26, 40 +G, 39, 26, 7, 2, 2, 76, 1, 44, 31 +Total, 232, 1, 114, 80, 4, 3, 39, 27, 500, 4, 260, 236 diff --git a/algorithm/2021F/lab_06/lab_06_A/CMakeLists.txt b/algorithm/2021F/lab_06/lab_06_A/CMakeLists.txt new file mode 100644 index 00000000..40897f09 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_A/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER A) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_06/lab_06_A/README.md b/algorithm/2021F/lab_06/lab_06_A/README.md new file mode 100644 index 00000000..2d9cc936 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_A/README.md @@ -0,0 +1,29 @@ +# lab_06_A — Different Substrings + +## Description + +Given a string , you are required to calculate how many different substrings it has. + +Here we define two strings are different if and only if they have different length or have at least one position where they have different characters + +## Input + +One line, indicating the string \(S\) \((1\leq |S|\leq 10^2)\) + +## Output + +One integer, indicating the answer. + +## Sample Input + +```log +aab +``` + +## Sample Output + +```log +5 +``` + +## HINT diff --git a/algorithm/2021F/lab_03/lab_03_D/lab_03_D.cpp b/algorithm/2021F/lab_06/lab_06_A/main.cpp similarity index 52% rename from algorithm/2021F/lab_03/lab_03_D/lab_03_D.cpp rename to algorithm/2021F/lab_06/lab_06_A/main.cpp index 9c634dc8..0de64114 100644 --- a/algorithm/2021F/lab_03/lab_03_D/lab_03_D.cpp +++ b/algorithm/2021F/lab_06/lab_06_A/main.cpp @@ -1,73 +1,62 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: 2020-2025 nanoseeds -#include -#include -#include -#include -#include #include -#include #include -#include -#include #include -#include -#include -#include +#include -#ifdef ALGORITHM_TEST_MACRO -namespace lab_03_D{ +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_06_A{ #endif - -using std::cin; using std::tie; +using std::cin; using std::cout; -using std::list; -using std::sort; -using std::array; -using std::deque; -using std::queue; -using std::stack; using std::tuple; -using std::string; using std::vector; -using std::unordered_map; -using std::unordered_set; -using std::priority_queue; +using std::set; static constexpr const char end{'\n'}; using num_t = int32_t; -using input_type = tuple; +using input_type = std::string; using output_type = num_t; inline input_type read(); -output_type cal(input_type data); +output_type cal(const input_type& data); void output(const output_type &data); int main() { - auto input_data = read(); - auto output_data = cal(input_data); + const auto input_data = read(); + const auto output_data = cal(input_data); output(output_data); return 0; } inline input_type read() { - num_t a{0}, b{0}; - std::cin >> a >> b; - return std::make_tuple(a, b); + input_type a; + std::cin >> a; + return a; } -output_type cal(input_type data) { - num_t a{0}, b{0}; - tie(a, b) = data; - num_t c = a + b; - return c; +output_type cal(const input_type& data) { + const int32_t n = static_cast(data.size()); + std::set subs; + for (int32_t i = 0; i < n; ++i) { + for (int32_t len = 1; i + len <= n; ++len) { + subs.insert(data.substr(i, len)); + } + } + return static_cast(subs.size()); } void output(const output_type &data) { - cout << data << end; + std::cout << data << end; } static const auto faster_streams = [] { @@ -81,6 +70,7 @@ static const auto faster_streams = [] { // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. return 0; }(); + #ifdef ALGORITHM_TEST_MACRO } #endif diff --git a/algorithm/2021F/lab_06/lab_06_A/resource/1.data.in b/algorithm/2021F/lab_06/lab_06_A/resource/1.data.in new file mode 100644 index 00000000..6f27bcf7 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_A/resource/1.data.in @@ -0,0 +1 @@ +aab diff --git a/algorithm/2021F/lab_06/lab_06_A/resource/1.data.out b/algorithm/2021F/lab_06/lab_06_A/resource/1.data.out new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_A/resource/1.data.out @@ -0,0 +1 @@ +5 diff --git a/algorithm/2021F/lab_06/lab_06_A/test.cpp b/algorithm/2021F/lab_06/lab_06_A/test.cpp new file mode 100644 index 00000000..4f585ee7 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_A/test.cpp @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_06/lab_06_A/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_06_A { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 06_A]", "[test 06_A]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_06/lab_06_B/CMakeLists.txt b/algorithm/2021F/lab_06/lab_06_B/CMakeLists.txt new file mode 100644 index 00000000..dac0839a --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_B/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER B) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_06/lab_06_B/README.md b/algorithm/2021F/lab_06/lab_06_B/README.md new file mode 100644 index 00000000..7f1be862 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_B/README.md @@ -0,0 +1,47 @@ +# lab_06_B — FSA Transition Function + +## Description + +As learned in the lecture, FSA can be used to solve string matching problems. + +Here you are given a string \(S\), and you are required to output it's transition function according to the FSA algorithm. + +## Input + +One line, indicating the input string \(S\) \((1\leq |S| \leq 10^5)\). + +The string contains only lowercase letters. + +## Output + +\(|S|\) lines, each containing 26 integers, indicating the transition function. + +## Sample Input + +```log +aabaaabb +``` + +## Sample Output + +```log +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +4 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +``` + +## HINT + +## 复用信息 + ++ Contest 1101:CS203 2021 Fall Lab 06 String ++ Contest 1102:CS217 2021 Fall Lab 06 String ++ Contest 1122:CS203 2022 Fall Lab 5 String ++ Contest 1123:CS217 2022 Fall Lab 5 String ++ Contest 1144:CS203 2023 Fall Lab 5 String ++ Contest 1170:CS203 2024 Fall Lab 5 diff --git a/algorithm/2021F/lab_06/lab_06_B/main.cpp b/algorithm/2021F/lab_06/lab_06_B/main.cpp new file mode 100644 index 00000000..c7519fbc --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_B/main.cpp @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_06_B { +#endif + +using std::string; +using std::vector; + +// Function to compute the KMP next array (prefix function) +auto compute_next(const string &pattern) -> vector { + const int32_t m = pattern.length(); + vector next(m, 0); + for (int32_t i = 1, j = 0; i < m; i++) { + while (j > 0 && pattern[i] != pattern[j]) { + j = next[j - 1]; + } + if (pattern[i] == pattern[j]) { + j++; + } + next[i] = j; + } + return next; +} + +// Function to compute the FSA transition function +auto compute_transition_function(const string &pattern) + -> vector> { + const int32_t m = pattern.length(); + const auto next = compute_next(pattern); + vector> delta(m, vector(26)); + + for (int32_t q = 0; q < m; ++q) { + for (char c_char = 'a'; c_char <= 'z'; ++c_char) { + const int32_t c_idx = c_char - 'a'; + if (c_char == pattern[q]) { + // On matching character, move to q+1 (may equal m) + delta[q][c_idx] = q + 1; + } else { + if (q > 0) { + delta[q][c_idx] = delta[next[q - 1]][c_idx]; + } else { + delta[q][c_idx] = 0; + } + } + } + } + return delta; +} + +auto solve() -> void { + string pattern; + std::cin >> pattern; + const auto delta = compute_transition_function(pattern); + for (const auto &row : delta) { + for (size_t i = 0; i < row.size(); ++i) { + std::cout << row[i] << (i == row.size() - 1 ? "" : " "); + } + std::cout << '\n'; + } +} + +int main() { + solve(); + return 0; +} +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_06/lab_06_B/resource/1.data.in b/algorithm/2021F/lab_06/lab_06_B/resource/1.data.in new file mode 100644 index 00000000..dcb01989 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_B/resource/1.data.in @@ -0,0 +1 @@ +aabaaabb diff --git a/algorithm/2021F/lab_06/lab_06_B/resource/1.data.out b/algorithm/2021F/lab_06/lab_06_B/resource/1.data.out new file mode 100644 index 00000000..f5802baf --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_B/resource/1.data.out @@ -0,0 +1,8 @@ +1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +6 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +2 7 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +4 8 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/algorithm/2021F/lab_06/lab_06_B/test.cpp b/algorithm/2021F/lab_06/lab_06_B/test.cpp new file mode 100644 index 00000000..9c155098 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_B/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_06/lab_06_B/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_06_B { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 06_B]", "[test 06_B]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_06/lab_06_C/CMakeLists.txt b/algorithm/2021F/lab_06/lab_06_C/CMakeLists.txt new file mode 100644 index 00000000..f07d2e4c --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_C/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER C) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_06/lab_06_C/README.md b/algorithm/2021F/lab_06/lab_06_C/README.md new file mode 100644 index 00000000..9e5f8480 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_C/README.md @@ -0,0 +1,33 @@ +# lab_06_C — KMP Next Array + +## Description + +Given a string `S` with length `n`, you are required to calculate its next array of the KMP algorithm. + +## Input + +One line containing `S` `(1<= |S| <= 10^6)` + +## Output + +`n` lines, each containing a integer, indicating the next array value of `S[i]` for `0 <= i <= len(s)-1` + +## Sample Input + +```log +ababc +``` + +## Sample Output + +```log +0 +0 +1 +2 +0 +``` + +## HINT + +`next[0] = 0` diff --git a/algorithm/2021F/lab_06/lab_06_C/main.cpp b/algorithm/2021F/lab_06/lab_06_C/main.cpp new file mode 100644 index 00000000..086099d9 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_C/main.cpp @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_06_C { +#endif + +using std::string; +using std::vector; + +// Function to compute the KMP next array (prefix function) +auto compute_next(const string &pattern) -> vector { + const int32_t m = pattern.length(); + vector next(m, 0); + for (int32_t i = 1, j = 0; i < m; i++) { + while (j > 0 && pattern[i] != pattern[j]) { + j = next[j - 1]; + } + if (pattern[i] == pattern[j]) { + j++; + } + next[i] = j; + } + return next; +} + +auto solve() -> void { + string pattern; + std::cin >> pattern; + const auto next = compute_next(pattern); + for (const auto &val : next) { + std::cout << val << '\n'; + } +} + +int main() { + solve(); + return 0; +} +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_06/lab_06_C/resource/1.data.in b/algorithm/2021F/lab_06/lab_06_C/resource/1.data.in new file mode 100644 index 00000000..17380656 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_C/resource/1.data.in @@ -0,0 +1 @@ +ababc diff --git a/algorithm/2021F/lab_06/lab_06_C/resource/1.data.out b/algorithm/2021F/lab_06/lab_06_C/resource/1.data.out new file mode 100644 index 00000000..5def7353 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_C/resource/1.data.out @@ -0,0 +1,5 @@ +0 +0 +1 +2 +0 diff --git a/algorithm/2021F/lab_06/lab_06_C/test.cpp b/algorithm/2021F/lab_06/lab_06_C/test.cpp new file mode 100644 index 00000000..664c4c60 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_C/test.cpp @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_06/lab_06_C/resource/";} + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_06_C { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 06_C]", "[test 06_C]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_06/lab_06_D/CMakeLists.txt b/algorithm/2021F/lab_06/lab_06_D/CMakeLists.txt new file mode 100644 index 00000000..564aeae5 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_D/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER D) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_06/lab_06_D/README.md b/algorithm/2021F/lab_06/lab_06_D/README.md new file mode 100644 index 00000000..40aec9df --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_D/README.md @@ -0,0 +1,35 @@ +# lab_06_D — Rotation Check + +## Description + +Given two strings `S,T`, you are required to judge if you can obtain one of the two strings by rotating the other one. + +## Input + +Two lines, indicating two strings `S,T ( 1 <= |S|,|T| <= 10^6 )` + +## Output + +One line, "Yes" (without quotes) if you can obtain one of the two strings by rotating the other one, "No" (without quotes) otherwise. + +## Sample Input + +```log +abcde cdeab +``` + +## Sample Output + +```log +Yes +``` + +## HINT + +`(abcde)` and `(cdeab)` -> Yes +`(abcde)` and `(edcba)` -> No +`(abcdeabcde)` and `(abcde)` -> No + +Example of rotating a string: + +`( abcde)` -> `(bcdea)` -> `( cdeab)` -> `(deabc)` -> `(eabcd)` -> `( abcde)` diff --git a/algorithm/2021F/lab_06/lab_06_D/main.cpp b/algorithm/2021F/lab_06/lab_06_D/main.cpp new file mode 100644 index 00000000..8c277b5d --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_D/main.cpp @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_06_D { +#endif +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +using std::string; +static constexpr const char end{'\n'}; + +using num_t = int32_t; +using input_type = tuple; +using output_type = string; + +inline input_type read(); + +output_type cal(const input_type &data); + +void output(const output_type &data); + +int main() { + const auto input_data = read(); + const auto output_data = cal(input_data); + output(output_data); + return 0; +} + +inline input_type read() { + string s, t; + // read two whitespace-separated strings (works for single-line or two-line inputs) + std::cin >> s >> t; + return std::make_tuple(std::move(s), std::move(t)); +} + +// KMP prefix (lps) computation +static vector build_lps(const string &pat) { + const num_t n = static_cast(pat.size()); + vector lps(n, 0); + num_t len = 0; + for (num_t i = 1; i < n; ++i) { + while (len > 0 && pat[i] != pat[len]) { + len = lps[len - 1]; + } + if (pat[i] == pat[len]) { + ++len; + lps[i] = len; + } + } + return lps; +} + +// KMP search: returns true if pattern exists in text +static bool kmp_search(const string &text, const string &pat) { + if (pat.empty()) return true; + const num_t n = static_cast(text.size()); + const num_t m = static_cast(pat.size()); + if (m > n) return false; + const auto lps = build_lps(pat); + num_t j = 0; // index in pat + for (num_t i = 0; i < n; ++i) { + while (j > 0 && text[i] != pat[j]) j = lps[j - 1]; + if (text[i] == pat[j]) { + ++j; + if (j == m) return true; + } + } + return false; +} + +static constexpr char *const YES{"Yes"}; +static constexpr char *const NO{"No"}; + +output_type cal(const input_type &data) { + string s, t; + tie(s, t) = data; + // If lengths differ, cannot be rotations + if (s.size() != t.size()) return NO; + // Quick equality check + if (s == t) return YES; + // Check if t is a substring of s+s using KMP + string doubled = s + s; + bool ok = kmp_search(doubled, t); + return ok ? YES : NO; +} + +void output(const output_type &data) { + std::cout << data << end; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_06/lab_06_D/resource/1.data.in b/algorithm/2021F/lab_06/lab_06_D/resource/1.data.in new file mode 100644 index 00000000..13b5fe2c --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_D/resource/1.data.in @@ -0,0 +1 @@ +abcde cdeab diff --git a/algorithm/2021F/lab_06/lab_06_D/resource/1.data.out b/algorithm/2021F/lab_06/lab_06_D/resource/1.data.out new file mode 100644 index 00000000..dcd7a5d6 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_D/resource/1.data.out @@ -0,0 +1 @@ +Yes diff --git a/algorithm/2021F/lab_06/lab_06_D/test.cpp b/algorithm/2021F/lab_06/lab_06_D/test.cpp new file mode 100644 index 00000000..70f35a55 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_D/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_06/lab_06_D/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_06_D { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 06_D]", "[test 06_D]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_06/lab_06_E/CMakeLists.txt b/algorithm/2021F/lab_06/lab_06_E/CMakeLists.txt new file mode 100644 index 00000000..f6252ecc --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_E/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER E) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_06/lab_06_E/README.md b/algorithm/2021F/lab_06/lab_06_E/README.md new file mode 100644 index 00000000..3f139f65 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_E/README.md @@ -0,0 +1,31 @@ +# lab_06_E — Longest Palindromic Substring + +## Description + +Given a string `S`, you are required to find the length of its longest palindromic substring. + +Here we define a string is palindromic if and only if you can get the exactly same string by reversing the original string. + +For example, string `abcba` is palindromic while `abcab` is not. + +## Input + +One line containing `S (1<= |S| <= 10^5)` + +## Output + +One integer, indicating the answer + +## Sample Input + +```log +abcbad +``` + +## Sample Output + +```log +5 +``` + +## HINT diff --git a/algorithm/2021F/lab_06/lab_06_E/main.cpp b/algorithm/2021F/lab_06/lab_06_E/main.cpp new file mode 100644 index 00000000..4c2735d0 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_E/main.cpp @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_06_E{ +#endif + +using std::cin; +using std::cout; +using std::string; +using std::vector; + +static constexpr const char end{'\n'}; + +using num_t = int32_t; +using input_type = std::tuple; +using output_type = num_t; + +inline input_type read(); +output_type cal(const input_type &data); +void output(const output_type &data); + +int main() { + const auto input_data = read(); + const auto output_data = cal(input_data); + output(output_data); + return 0; +} + +inline input_type read() { + string s; + std::cin >> s; + return std::make_tuple(std::move(s)); +} + +// Manacher simplified via d1 (odd) and d2 (even) radii arrays +output_type cal(const input_type &data) { + string s; + std::tie(s) = data; + const num_t n = static_cast(s.size()); + if (n <= 0) return 0; + + vector d1(n); // odd + num_t l = 0, r = -1; + for (num_t i = 0; i < n; ++i) { + num_t k = (i > r) ? 1 : std::min(d1[l + r - i], r - i + 1); + while (i - k >= 0 && i + k < n && s[i - k] == s[i + k]) ++k; + d1[i] = k; + if (i + k - 1 > r) { + l = i - k + 1; + r = i + k - 1; + } + } + + vector d2(n); // even + l = 0; r = -1; + for (num_t i = 0; i < n; ++i) { + num_t k = (i > r) ? 0 : std::min(d2[l + r - i + 1], r - i + 1); + while (i - k - 1 >= 0 && i + k < n && s[i - k - 1] == s[i + k]) ++k; + d2[i] = k; + if (i + k - 1 > r) { + l = i - k; + r = i + k - 1; + } + } + + num_t best = 1; + for (num_t i = 0; i < n; ++i) { + const num_t len1 = d1[i] * 2 - 1; + if (len1 > best) best = len1; + const num_t len2 = d2[i] * 2; + if (len2 > best) best = len2; + } + return best; +} + +void output(const output_type &data) { + std::cout << data << end; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_06/lab_06_E/resource/1.data.in b/algorithm/2021F/lab_06/lab_06_E/resource/1.data.in new file mode 100644 index 00000000..1bf32437 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_E/resource/1.data.in @@ -0,0 +1 @@ +abcbad diff --git a/algorithm/2021F/lab_06/lab_06_E/resource/1.data.out b/algorithm/2021F/lab_06/lab_06_E/resource/1.data.out new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_E/resource/1.data.out @@ -0,0 +1 @@ +5 diff --git a/algorithm/2021F/lab_06/lab_06_E/test.cpp b/algorithm/2021F/lab_06/lab_06_E/test.cpp new file mode 100644 index 00000000..0da21d63 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_E/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_06/lab_06_E/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_06_E { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 06_E]", "[test 06_E]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_06/lab_06_F/CMakeLists.txt b/algorithm/2021F/lab_06/lab_06_F/CMakeLists.txt new file mode 100644 index 00000000..3bd8bb2b --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_F/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER F) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_06/lab_06_F/README.md b/algorithm/2021F/lab_06/lab_06_F/README.md new file mode 100644 index 00000000..d832db7c --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_F/README.md @@ -0,0 +1,47 @@ +# lab_06_F — Minimal Half Length (Substitution Cipher) + +## Description + +There is a string `S_0` with length `2m`. + +Its first half `S_0[1,m]` is the substitution cipher of the second half `S_0[m+1,2m]`. + +Then for some reason, the second half of `S_0` may lose some characters at the end, resulting in string `S`. + +Given this string `S`, you need to answer the smallest possible value of `m`. + +Hint: substitution cipher is an encryption method that replaces letters in the text with other letters. + +For example, if our encryption rule is `a->c,b->a,c->b`, then the string "accb" will be encrypted into "cbba". + +## Input + +The first line is the code table for the substitution cipher, which contains 26 letters representing the encrypted letter for each letter in lexicographical order. + +The second line is `S (1<= |S| <= 5*10^5)`. + +## Output + +One integer, indicating the minimal possible length of the second half. + +## Sample Input + +```log +b c d e f g h i j k l m n o p q r s t u v w x y z a +bcdeabc +``` + +## Sample Output + +```log +4 +``` + +## HINT + +## 复用信息 + ++ Contest 1101:CS203 2021 Fall Lab 06 String ++ Contest 1102:CS217 2021 Fall Lab 06 String ++ Contest 1144:CS203 2023 Fall Lab 5 String ++ Contest 1170:CS203 2024 Fall Lab 5 diff --git a/algorithm/2021F/lab_06/lab_06_F/main.cpp b/algorithm/2021F/lab_06/lab_06_F/main.cpp new file mode 100644 index 00000000..ba07f54b --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_F/main.cpp @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_06_F{ +#endif +using std::cin; +using std::cout; +using std::vector; +using std::string; +using std::array; +using std::pair; +static constexpr const char end{'\n'}; + +using num_t = int32_t; +using input_type = pair, string>; +using output_type = num_t; + +inline input_type read_input(); + +output_type cal(const input_type& data); + +void output(const output_type &data); + +int main() { + const auto input_data = read_input(); + const auto output_data = cal(input_data); + output(output_data); + return 0; +} + +inline input_type read_input() { + array mp{}; + for (int i = 0; i < 26; ++i) { + cin >> mp[i]; + } + string s; + cin >> s; + return {mp, s}; +} + +output_type cal(const input_type& data) { + const auto& mp = data.first; + const string& s = data.second; + // Build f(s) where f is the provided substitution mapping + int n = static_cast(s.size()); + string fs; + fs.resize(n); + for (int i = 0; i < n; ++i) { + fs[i] = mp[s[i] - 'a']; + } + // KMP prefix function for pattern = s + vector pi(n); + for (int i = 1; i < n; ++i) { + int j = pi[i-1]; + while (j > 0 && s[i] != s[j]) j = pi[j-1]; + if (s[i] == s[j]) ++j; + pi[i] = j; + } + // Match pattern s over text fs; after processing whole text, j is the + // length of the longest prefix of s that is a suffix of fs + int j = 0; + for (int i = 0; i < n; ++i) { + while (j > 0 && fs[i] != s[j]) j = pi[j-1]; + if (fs[i] == s[j]) ++j; + if (j == n) { // full match, move j to proper border + j = pi[j-1]; + } + } + int max_p = j; + int half = n / 2; + if (max_p > half) max_p = half; + return static_cast(n - max_p); +} + +void output(const output_type &data) { + cout << data << end; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_06/lab_06_F/resource/1.data.in b/algorithm/2021F/lab_06/lab_06_F/resource/1.data.in new file mode 100644 index 00000000..68dc8f1b --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_F/resource/1.data.in @@ -0,0 +1,2 @@ +b c d e f g h i j k l m n o p q r s t u v w x y z a +bcdeabc diff --git a/algorithm/2021F/lab_06/lab_06_F/resource/1.data.out b/algorithm/2021F/lab_06/lab_06_F/resource/1.data.out new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_F/resource/1.data.out @@ -0,0 +1 @@ +4 diff --git a/algorithm/2021F/lab_06/lab_06_F/test.cpp b/algorithm/2021F/lab_06/lab_06_F/test.cpp new file mode 100644 index 00000000..b8228730 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_F/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_06/lab_06_F/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_06_F { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 06_F]", "[test 06_F]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_06/lab_06_G/CMakeLists.txt b/algorithm/2021F/lab_06/lab_06_G/CMakeLists.txt new file mode 100644 index 00000000..768dc1e2 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_G/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER G) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_06/lab_06_G/README.md b/algorithm/2021F/lab_06/lab_06_G/README.md new file mode 100644 index 00000000..a63658d1 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_G/README.md @@ -0,0 +1,31 @@ +# lab_06_G — Border Occurrence (Prefix-Suffix-Inner) + +## Description + +Given you a String `S`, you are required to find the longest string that shows in `S`'s prefix, suffix and also shows in `S`'s inner place. + +Here we define the inner place of a string is the substring without its first and last character. + +For example, the inner place of string `abcde` is `bcd`. + +## Input + +One line containing `S (1<= |S| <= 10^6)` + +## Output + +If you can find such a string, print it, otherwise print "Just a legend" (without quote) + +## Sample Input + +```log +abababa +``` + +## Sample Output + +```log +aba +``` + +## HINT diff --git a/algorithm/2021F/lab_06/lab_06_G/main.cpp b/algorithm/2021F/lab_06/lab_06_G/main.cpp new file mode 100644 index 00000000..31137b96 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_G/main.cpp @@ -0,0 +1,83 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_06_G{ +#endif +using std::cin; +using std::cout; +using std::string; +using std::vector; +static constexpr const char end{'\n'}; +using output_type = string; + +inline string read_input(); + +output_type cal(const string& s); + +void output(const output_type &data); + +int main() { + const auto s = read_input(); + const auto ans = cal(s); + output(ans); + return 0; +} + +inline string read_input() { + string s; + std::cin >> s; + return s; +} + +output_type cal(const string& s) { + const int n = static_cast(s.size()); + if (n <= 2) return string("Just a legend"); + vector pi(n, 0); + for (int i = 1; i < n; ++i) { + int j = pi[i-1]; + while (j > 0 && s[i] != s[j]) j = pi[j-1]; + if (s[i] == s[j]) ++j; + pi[i] = j; + } + int len = pi[n-1]; + // Check if this len appears in the prefix function except at last position + while (len > 0) { + bool found = false; + for (int i = 0; i < n-1; ++i) { + if (pi[i] == len) { found = true; break; } + } + if (found) return s.substr(0, len); + len = pi[len-1]; + } + return string("Just a legend"); +} + +void output(const output_type &data) { + cout << data << end; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_06/lab_06_G/resource/1.data.in b/algorithm/2021F/lab_06/lab_06_G/resource/1.data.in new file mode 100644 index 00000000..e3045825 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_G/resource/1.data.in @@ -0,0 +1 @@ +abababa diff --git a/algorithm/2021F/lab_06/lab_06_G/resource/1.data.out b/algorithm/2021F/lab_06/lab_06_G/resource/1.data.out new file mode 100644 index 00000000..d9265f82 --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_G/resource/1.data.out @@ -0,0 +1 @@ +aba diff --git a/algorithm/2021F/lab_06/lab_06_G/test.cpp b/algorithm/2021F/lab_06/lab_06_G/test.cpp new file mode 100644 index 00000000..8285d63f --- /dev/null +++ b/algorithm/2021F/lab_06/lab_06_G/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_06/lab_06_G/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_06_G { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 06_G]", "[test 06_G]") { + CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_07/CMakeLists.txt b/algorithm/2021F/lab_07/CMakeLists.txt new file mode 100644 index 00000000..2094b775 --- /dev/null +++ b/algorithm/2021F/lab_07/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROJECT_ORDER lab_07) +project(${PROJECT_NAME}_${PROJECT_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +set(dependencies A B C D E F G) +foreach (elementName IN LISTS dependencies) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${elementName}) +endforeach () +unset(dependencies) diff --git a/algorithm/2021F/lab_07/README.md b/algorithm/2021F/lab_07/README.md new file mode 100644 index 00000000..dc4971f5 --- /dev/null +++ b/algorithm/2021F/lab_07/README.md @@ -0,0 +1,33 @@ +# Contest1104 - CS203 2021 Fall Lab 07 Tree + +> cid: 1103 + +Welcome to CS203 2021 Fall Lab 07! Enjoy this Lab! + +There are six problems for you to solve. + +Score: + +- A: 10 +- B: 15/10 +- C: 15/10 +- D: 20/15 +- E: 20/15 +- F: 20 +- G: undefined/20 + +Reading the samples and hints carefully can help you understand the problem. + +## Contest Problems + +| Problem | problem id | +|---:|---:| +| A | 1453 | +| B | 1454 | +| C | 1455 | +| D | 1456 | +| E | 1457 | +| F | 1458 | +| G | 1459 | + +A, B 被复用 diff --git a/algorithm/2021F/lab_07/cs203.submit.csv b/algorithm/2021F/lab_07/cs203.submit.csv new file mode 100644 index 00000000..f4ceab99 --- /dev/null +++ b/algorithm/2021F/lab_07/cs203.submit.csv @@ -0,0 +1,8 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 226, 201, 44, 7, 3, 58, 51, 590, 20, 139, 431 +B, 300, 1, 83, 107, 9, 23, 33, 556, 6, 112, 438 +C, 231, 4, 48, 11, 5, 16, 165, 28, 508, 2, 76, 430 +D, 232, 10, 248, 12, 11, 118, 24, 655, 10, 115, 530 +E, 182, 5, 402, 122, 7, 58, 307, 54, 1137, 6, 214, 917 +F, 183, 3, 536, 244, 57, 2, 337, 42, 1404, 2, 251, 1151 +Total, 1354, 23, 1518, 540, 85, 90, 1008, 232, 4850, 46, 907, 3897 diff --git a/algorithm/2021F/lab_07/cs217.submit.csv b/algorithm/2021F/lab_07/cs217.submit.csv new file mode 100644 index 00000000..a1ee721c --- /dev/null +++ b/algorithm/2021F/lab_07/cs217.submit.csv @@ -0,0 +1,9 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 33, 15, 3, 1, 3, 55, 3, 28, 24 +B, 41, 5, 9, 1, 6, 3, 65, 39, 26 +C, 36, 1, 9, 1, 6, 5, 58, 4, 32, 22 +D, 27, 13, 2, 12, 4, 58, 1, 25, 32 +E, 42, 47, 7, 2, 1, 14, 7, 120, 53, 67 +F, 34, 41, 14, 3, 1, 29, 8, 130, 62, 68 +G, 43, 57, 13, 11, 6, 130, 64, 66 +Total, 256, 1, 187, 47, 6, 4, 79, 36, 616, 8, 303, 305 diff --git a/algorithm/2021F/lab_07/lab_07_A/CMakeLists.txt b/algorithm/2021F/lab_07/lab_07_A/CMakeLists.txt new file mode 100644 index 00000000..40897f09 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_A/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER A) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_07/lab_07_A/README.md b/algorithm/2021F/lab_07/lab_07_A/README.md new file mode 100644 index 00000000..948c2b72 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_A/README.md @@ -0,0 +1,67 @@ +## Description + +Given a rooted tree numbered from $1$ to $n$, each edge has a weight $w$. + +The root node of the tree is node $1$. + +You are asked to calculate the number of paths that start from the root, terminate in a leaf node, and satisfy the sum of edge weights in the path equals to $num$. + +### Input + +The first line contains two integers $n$ and $num$ $(1 \le n \le 500000, 1 \le num \le 2000000000)$, indicating the number of tree nodes and the target number. + +Then $n-1$ lines follow. Each line contains three integers $u, v, w$ $(1 \le u, v \le n, 1 \le w \le 100)$ describing an edge. The first two integers are the indices of nodes that form an edge and the last integer indicates the weight of the edge. + +### Output + +Output an integer which means how many paths satisfying the sum of edge weights in the path equals to $num$. + +### Sample Input + +``` log +6 6 +1 2 2 +1 3 3 +3 4 4 +3 5 3 +2 6 4 +``` + +### Sample Output + +``` log +2 +``` + +### HINT + +Paths must start at root (1) and end at a leaf. + +Count those whose sum of edge weights equals the target $num$. + +## 复用信息 + ++ Contest 1125:CS217 2022 Fall Lab 6 Tree ++ Contest 1103:CS217 2021 Fall Lab 07 Tree ++ Contest 1104:CS203 2021 Fall Lab 07 Tree ++ Contest 1124:CS203 2022 Fall Lab 6 Tree ++ Contest 1148:CS203 2023 Fall Lab 6 Tree ++ Contest 1174:CS203 2024 Fall Lab 6 + +### 算法分析 + +实现使用链式前向星(head + edges 数组)来表示树并在读入阶段构建图。 + +随后从根节点 1 开始使用显式栈进行迭代深度优先遍历,计算每个节点到根的路径和(path-sum)。 + +当遍历到子节点时,将父节点的 path-sum 加上该边权重作为子节点的 path-sum,这样可以在线性时间内得到所有节点的路径和。 + +一个节点被判定为叶子当且仅当它在遍历时没有除父节点外的子节点;最终统计所有叶子中 path-sum 等于目标 `num` 的个数。 + +实现采用显式栈而非递归,以避免在 n 很大(<=5e5)时发生栈溢出。 + +时间复杂度为 O(n),空间复杂度为 O(n),其中 n 为节点数,主要开销来自前向星邻接结构及若干辅助数组。 + +代码遵循三段式结构(read -> solve -> write),并使用定长整数类型保证稳定性和可移植性。 + +实现考虑了单节点和深链等边界情况,迭代遍历和前向星结构能稳健处理这些情形。 diff --git a/algorithm/2021F/lab_07/lab_07_A/main.cpp b/algorithm/2021F/lab_07/lab_07_A/main.cpp new file mode 100644 index 00000000..1dc0e8bc --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_A/main.cpp @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include + +namespace tree { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { +public: + // 边的结构体定义 + std::vector head; // head[i] 存储顶点i的第一条边的索引 + std::vector edges; // 存储所有边的数组 + int32_t edge_count; // 当前边的总数 +public: + /** + * @brief 构造函数 + * @param num_nodes 顶点的数量 (假设顶点编号从 1 到 num_nodes) + * @param max_edges 预估的最大边数 (对于无向图,一条无向边算两条有向边) + */ + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + // 初始化头节点数组,大小为顶点数+1,方便1-based 索引 + // 所有顶点的初始头节点都设为-1,表示没有出边 + head.assign(num_nodes + 1, -1); + // 预分配存储所有边的空间 + edges.resize(max_edges); + } + + /** + * @brief 添加一条有向边 + * @param u 起点 + * @param v 终点 + * @param w 权重 + */ + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + // 在边数组的末尾添加新边 + edges[edge_count].to = v; + edges[edge_count].weight = w; + // 新边的 next 指向原来以 u 为起点的第一条边 + edges[edge_count].next = head[u]; + // 更新以 u 为起点的第一条边为当前新添加的边 + head[u] = edge_count; + // 边计数器加一 + edge_count++; + } + + /** + * @brief 添加一条无向边 + * @param u, v 顶点 + * @param w 权重 + */ + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + add_edge(u, v, w); + add_edge(v, u, w); + } +}; +} + + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_07_A { +#endif +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +static constexpr const char end{'\n'}; + +// reuse tree::Edge defined above in namespace tree + +// Input / Processing / Output three-stage implementation + +// using num_t alias already declared above +struct Input { + int32_t n{0}; + int64_t target{0}; + tree::Graph graph; // constructed during read + // Default constructor must initialize graph to avoid deleted default + Input(): graph(0, 0) { + } +}; + +using output_type = int64_t; + +// Read: parse input into Input struct +static Input read_input() { + Input in{}; + if (!(cin >> in.n >> in.target)) { + return in; + } + const int32_t max_edges = std::max(1, (in.n - 1) * 2); + in.graph = tree::Graph(in.n, max_edges); + int32_t u, v, w; + for (int32_t i = 0; i < in.n - 1; ++i) { + cin >> u >> v >> w; + in.graph.add_undirected_edge(u, v, w); + } + return in; +} + +// Process: compute number of root-to-leaf paths whose edge-weight sum == target +static output_type solve(const Input &in) { + const auto n = in.n; + const auto target = in.target; + const auto graph = in.graph; + + // iterative DFS from root=1 to compute parent and path sums using graph.head & graph.edges + std::vector parent(n + 1, -1); + std::vector path_sum(n + 1, 0); + parent[1] = 0; + std::vector st; + st.reserve(n); + st.push_back(1); + while (!st.empty()) { + const auto u = st.back(); + st.pop_back(); + for (int32_t ei = graph.head[u]; ei != -1; ei = graph.edges[ei].next) { + const auto v = graph.edges[ei].to; + const auto w = graph.edges[ei].weight; + if (v == parent[u]) { + continue; + } + parent[v] = u; + path_sum[v] = path_sum[u] + w; + st.push_back(v); + } + } + + // count leaves whose path_sum equals target + int64_t ans = 0; + for (int32_t u = 1; u <= n; ++u) { + bool is_leaf = true; + for (int32_t ei = graph.head[u]; ei != -1; ei = graph.edges[ei].next) { + const auto v = graph.edges[ei].to; + if (v == parent[u]) continue; + is_leaf = false; + break; + } + if (is_leaf && path_sum[u] == target) ++ans; + } + return ans; +} + +// Output: print result +static void write_output(const output_type &out) { + cout << out << end; +} + +int main() { + // faster_streams static initializer handles ios sync and ties + const auto input = read_input(); + // if no valid input (e.g., empty), exit + if (input.n <= 0) { return 0; } + const auto result = solve(input); + write_output(result); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_07/lab_07_A/resource/01.data.in b/algorithm/2021F/lab_07/lab_07_A/resource/01.data.in new file mode 100644 index 00000000..00b42bd5 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_A/resource/01.data.in @@ -0,0 +1,6 @@ +6 6 +1 2 2 +1 3 3 +3 4 4 +3 5 3 +2 6 4 diff --git a/algorithm/2021F/lab_07/lab_07_A/resource/01.data.out b/algorithm/2021F/lab_07/lab_07_A/resource/01.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_A/resource/01.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_03/lab_03_D/lab_03_D_test.cpp b/algorithm/2021F/lab_07/lab_07_A/test.cpp similarity index 58% rename from algorithm/2021F/lab_03/lab_03_D/lab_03_D_test.cpp rename to algorithm/2021F/lab_07/lab_07_A/test.cpp index b1f14950..4df6cb10 100644 --- a/algorithm/2021F/lab_03/lab_03_D/lab_03_D_test.cpp +++ b/algorithm/2021F/lab_07/lab_07_A/test.cpp @@ -8,15 +8,37 @@ #include #include -#include "lab_03_D.cpp" - -std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_03/lab_03_D/resource/"; } +#include "main.cpp" +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_07/lab_07_A/resource/"; } const std::string CS203_redirect::file_paths = getFilePath(); -namespace lab_03_D { +// 测试链式前向星数据结构 +namespace tree { +TEST_CASE("Graph chain forward star basic", "[graph]") { + using tree::Graph; + using std::vector; + using std::pair; + Graph g(3, 4); // 3个节点, 最多四条边 + g.add_undirected_edge(1, 2, 5); // 边 1-2/2-1,权重为 5 + g.add_edge(2, 3, 7); // 边 2-3,权重为 7 + vector > > expected(4); + // Directed edges stored outgoing: insertion order newest-first + expected[1] = {{2, 5}}; + expected[2] = {{3, 7}, {1, 5}}; + expected[3] = {}; // no outgoing edges for node 3 + for (int u = 1; u <= 3; ++u) { + vector > got; + for (int eid = g.head[u]; eid != -1; eid = g.edges[eid].next) { + got.emplace_back(g.edges[eid].to, g.edges[eid].weight); + } + CHECK_THAT(got, Catch::Matchers::UnorderedEquals(expected[u])); + } +} +} // namespace tree +namespace lab_07_A { using std::tie; using std::cin; using std::cout; @@ -27,20 +49,9 @@ using Catch::Matchers::Equals; using Catch::Matchers::UnorderedEquals; using Catch::Matchers::Contains; -TEST_CASE("test case 1", "[test 03 D]") { - const auto output_data = cal(std::make_tuple(114, 514)); - CHECK(output_data == 628); - CHECK(1 + 2 == 3); - vector vec{2, 7, 11, 15}; - SECTION("CHECK_THAT 1") { - CHECK_THAT(vec, Contains({2})); - }SECTION("vec matcher") { - CHECK_THAT(vec, UnorderedEquals({15, 11, 7, 2})); - } -} // 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` -TEST_CASE("test case with sequence", "[test 03 D][.]") { - CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] +TEST_CASE("test case with sequence [test 07_A]", "[test 07_A]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out diff --git a/algorithm/2021F/lab_07/lab_07_B/CMakeLists.txt b/algorithm/2021F/lab_07/lab_07_B/CMakeLists.txt new file mode 100644 index 00000000..dac0839a --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_B/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER B) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_07/lab_07_B/README.md b/algorithm/2021F/lab_07/lab_07_B/README.md new file mode 100644 index 00000000..662f3190 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_B/README.md @@ -0,0 +1,54 @@ +## Description + +Given a tree whose nodes are numbered from 1 to $n$. + +You are asked to print all the leaf nodes of the tree in ascending order. + +The root of the tree is node 1. + +### Input + +The first line contains one integer $n$ $(1 \le n \le 1000000)$, indicating the number of nodes in the tree. + +Then $n-1$ lines follow. Each line contains two integers $u, v$ $(1 \le u, v \le n)$ describing an edge, indicating the indices of nodes which form an edge. + +### Output + +One line contains integers in ascending order. + +Multiple integers in one line must be separated by one space. + +### Sample Input + +``` log +4 +1 2 +1 3 +3 4 +``` + +### Sample Output + +``` log +2 4 +``` + +### HINT + +## 复用信息 + ++ Contest 1148:CS203 2023 Fall Lab 6 Tree ++ Contest 1103:CS217 2021 Fall Lab 07 Tree ++ Contest 1104:CS203 2021 Fall Lab 07 Tree + +### 算法分析 + +实现使用链式前向星(head + edges 数组)来表示无根树并在读入阶段构建图。 + +程序通过遍历每个节点的出边数来计算度数,注意图中采用了双向边存储,因此内部度数为实际度的两倍,但判断叶子时仅需判断除根以外节点的出边数是否为1。 + +当 n==1 时单独处理,直接输出 1 作为叶子。 + +最终将所有叶子结点收集后排序并按升序输出。 + +时间复杂度为 O(n),空间复杂度为 O(n)。 diff --git a/algorithm/2021F/lab_07/lab_07_B/main.cpp b/algorithm/2021F/lab_07/lab_07_B/main.cpp new file mode 100644 index 00000000..7f95e020 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_B/main.cpp @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include + +namespace tree { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { +public: + // 边的结构体定义 + std::vector head; // head[i] 存储顶点i的第一条边的索引 + std::vector edges; // 存储所有边的数组 + int32_t edge_count; // 当前边的总数 +public: + /** + * @brief 构造函数 + * @param num_nodes 顶点的数量 (假设顶点编号从 1 到 num_nodes) + * @param max_edges 预估的最大边数 (对于无向图,一条无向边算两条有向边) + */ + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + // 初始化头节点数组,大小为顶点数+1,方便1-based 索引 + // 所有顶点的初始头节点都设为-1,表示没有出边 + head.assign(num_nodes + 1, -1); + // 预分配存储所有边的空间 + edges.resize(max_edges); + } + + /** + * @brief 添加一条有向边 + * @param u 起点 + * @param v 终点 + * @param w 权重 + */ + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + // 在边数组的末尾添加新边 + edges[edge_count].to = v; + edges[edge_count].weight = w; + // 新边的 next 指向原来以 u 为起点的第一条边 + edges[edge_count].next = head[u]; + // 更新以 u 为起点的第一条边为当前新添加的边 + head[u] = edge_count; + // 边计数器加一 + edge_count++; + } + + /** + * @brief 添加一条无向边 + * @param u, v 顶点 + * @param w 权重 + */ + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + add_edge(u, v, w); + add_edge(v, u, w); + } +}; +} + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_07_B { +#endif +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +static constexpr const char end{'\n'}; + +// Input / Process / Output three-stage structure + + +struct Input { + int32_t n{0}; + std::shared_ptr graph; +}; + +using output_type = std::vector; + +static Input read_input() { + Input in{}; + if (!(cin >> in.n)) return in; + const int32_t max_edges = std::max(1, (in.n - 1) * 2); + in.graph = std::make_shared(in.n, max_edges); + for (int i = 0; i < in.n - 1; ++i) { + int32_t u, v; + cin >> u >> v; + in.graph->add_undirected_edge(u, v, 0); + } + return in; +} + +// collect leaves (nodes with degree 1), excluding root unless n==1 +static output_type solve(const Input &in) { + const auto n = in.n; + const auto &graph = *in.graph; + output_type leaves; + if (n <= 0) return leaves; + if (n == 1) { + leaves.push_back(1); + return leaves; + } + // degree = count of outgoing edges (because graph stores both directions) + for (int u = 1; u <= n; ++u) { + int deg = 0; + for (int ei = graph.head[u]; ei != -1; ei = graph.edges[ei].next) ++deg; + if (u != 1 && deg == 1) leaves.push_back(u); + } + std::sort(leaves.begin(), leaves.end()); + return leaves; +} + +static void write_output(const output_type &outv) { + for (size_t i = 0; i < outv.size(); ++i) { + if (i) cout << ' '; + cout << outv[i]; + } + cout << end; +} + +int main() { + const auto in = read_input(); + if (in.n <= 0) return 0; + const auto outv = solve(in); + write_output(outv); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_07/lab_07_B/resource/01.data.in b/algorithm/2021F/lab_07/lab_07_B/resource/01.data.in new file mode 100644 index 00000000..a15dcd96 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_B/resource/01.data.in @@ -0,0 +1,4 @@ +4 +1 2 +1 3 +3 4 diff --git a/algorithm/2021F/lab_07/lab_07_B/resource/01.data.out b/algorithm/2021F/lab_07/lab_07_B/resource/01.data.out new file mode 100644 index 00000000..0efd67f9 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_B/resource/01.data.out @@ -0,0 +1 @@ +2 4 diff --git a/algorithm/2021F/lab_07/lab_07_B/test.cpp b/algorithm/2021F/lab_07/lab_07_B/test.cpp new file mode 100644 index 00000000..7a237609 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_B/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_07/lab_07_B/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_07_B { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 07_B]", "[test 07_B]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_07/lab_07_C/CMakeLists.txt b/algorithm/2021F/lab_07/lab_07_C/CMakeLists.txt new file mode 100644 index 00000000..f07d2e4c --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_C/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER C) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_07/lab_07_C/README.md b/algorithm/2021F/lab_07/lab_07_C/README.md new file mode 100644 index 00000000..5153d841 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_C/README.md @@ -0,0 +1,48 @@ +## Description + +There is a complete binary tree, and you will get the number of nodes in this tree. + +You are asked to find the height of the tree. + +Notice that the height of a leaf node is $1$, and the height of any other node equals the maximum height among all subtrees plus one. + +And The height of a tree equals the height of the root node in the tree. + +### Input + +The first line contains one integer $T$ $(1 \le T \le 100000)$, which denotes the number of the test cases. + +Then $T$ lines follow. Each line contains an integer $num$ $(1 \le num \le 10^{18})$, which denotes number of the nodes in this tree. + +### Output + +$T$ lines. + +Each line contains one integer denotes the height of the tree in that case. + +### Sample Input + +``` log +3 +3 +4 +5 +``` + +### Sample Output + +``` log +2 +3 +3 +``` + +### HINT + +### 算法分析 + +对于给定节点数 n 的完全二叉树,其高度等价于二进制位数,计算方法为 floor(log2(n)) + 1。 + +实现中将 n 右移并计数得到高度,避免使用浮点运算以提高精度和性能。 + +程序为每个测试用例独立计算高度,整体时间复杂度为 O(T * log n) ,但对于给定约束可视为 O(T)。 diff --git a/algorithm/2021F/lab_07/lab_07_C/main.cpp b/algorithm/2021F/lab_07/lab_07_C/main.cpp new file mode 100644 index 00000000..1d879bf1 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_C/main.cpp @@ -0,0 +1,88 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +// Input / Process / Output three-stage implementation +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_07_C { +#endif +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +static constexpr const char end{'\n'}; + +struct Input { + int64_t T{0}; + std::vector nums; // values up to 1e18 +}; + +using output_type = std::vector; + +static Input read_input() { + Input in{}; + if (!(cin >> in.T)) return in; + in.nums.reserve(static_cast(in.T)); + for (int64_t i = 0; i < in.T; ++i) { + uint64_t x; + cin >> x; + in.nums.push_back(x); + } + return in; +} + +// compute height = floor(log2(n)) + 1 +static inline uint64_t compute_height(uint64_t n) { + if (n == 0) return 0; // undefined but guard + uint64_t h = 0; + while (n > 0) { + ++h; + n >>= 1; + } + return h; +} + +static output_type solve(const Input &in) { + output_type out; + out.reserve(in.nums.size()); + for (const auto &x: in.nums) out.push_back(compute_height(x)); + return out; +} + +static void write_output(const output_type &outv) { + for (const auto &v: outv) cout << v << end; +} + +int main() { + const auto in = read_input(); + if (in.T <= 0) return 0; + const auto outv = solve(in); + write_output(outv); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_07/lab_07_C/resource/01.data.in b/algorithm/2021F/lab_07/lab_07_C/resource/01.data.in new file mode 100644 index 00000000..67b7c2fd --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_C/resource/01.data.in @@ -0,0 +1,4 @@ +3 +3 +4 +5 diff --git a/algorithm/2021F/lab_07/lab_07_C/resource/01.data.out b/algorithm/2021F/lab_07/lab_07_C/resource/01.data.out new file mode 100644 index 00000000..4e8a2de2 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_C/resource/01.data.out @@ -0,0 +1,3 @@ +2 +3 +3 diff --git a/algorithm/2021F/lab_07/lab_07_C/test.cpp b/algorithm/2021F/lab_07/lab_07_C/test.cpp new file mode 100644 index 00000000..ce94744b --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_C/test.cpp @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_07/lab_07_C/resource/";} + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_07_C { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 07_C]", "[test 07_C]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_07/lab_07_D/CMakeLists.txt b/algorithm/2021F/lab_07/lab_07_D/CMakeLists.txt new file mode 100644 index 00000000..564aeae5 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_D/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER D) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_07/lab_07_D/README.md b/algorithm/2021F/lab_07/lab_07_D/README.md new file mode 100644 index 00000000..ce5ed383 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_D/README.md @@ -0,0 +1,43 @@ +## Description + +Given the order of a tree's pre-order traversal and post-order traversal, you are asked to find out how many distinct binary trees fit the given traversal orders. + +### Input + +The first line contains one integer $T$, which denotes the number of the test cases $(1 \le T \le 10000)$. + +The nodes of a binary tree are represented by capital letters, and no two distinct nodes are represented with the same letter. + +In each case, the first line contains a string $S_{pre}$, denoting the access order of the pre-order traversal. + +The second line contains a string $S_{post}$, denoting the access order of the post-order traversal $(|S_{pre}|, |S_{post}|\le 26)$. + +### Output + +Output the number of binary trees which meet the requirements. + +### Sample Input + +``` log +1 +ABCD +DCBA +``` + +### Sample Output + +``` log +8 +``` + +### HINT + +### 算法分析 + +利用先序与后序遍历信息递归划分树的子区间,预处理后序遍历中每个字符的位置以便快速定位子树范围。 + +递归函数对先序区间和后序区间进行匹配,逐个拆分子树并对每个子树递归求解,若某节点只有一个子树则其左右子树互换导致可行构造数翻倍。 + +边界情况包括空树和单节点树,均返回 1。 + +由于每个节点被处理一次,算法时间复杂度为 O(m)(m 为字符串长度,<=26),空间复杂度为 O(m)。 diff --git a/algorithm/2021F/lab_07/lab_07_D/main.cpp b/algorithm/2021F/lab_07/lab_07_D/main.cpp new file mode 100644 index 00000000..9c4d4b2e --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_D/main.cpp @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_07_D { +#endif +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +static constexpr const char end{'\n'}; + +struct Input { + int T{0}; + std::vector> cases; +}; + +using output_type = std::vector; + +static Input read_input() { + Input in{}; + if (!(cin >> in.T)) return in; + in.cases.reserve(std::max(0, in.T)); + for (int i = 0; i < in.T; ++i) { + std::string pre, post; + cin >> pre >> post; + in.cases.emplace_back(pre, post); + } + return in; +} + +// recursive solver: returns number of binary trees for given pre[pl..pr] and post[ol..or] +static long long solve_one(const std::string &pre, int pl, int pr, + const std::string &post, int ol, int orr, + const std::unordered_map &pos) { + if (pl > pr) return 1; + if (pl == pr) return 1; // single node + long long ways = 1; + int children = 0; + int i = pl + 1; // next position in pre for children + int o = ol; + while (i <= pr) { + char rootChild = pre[i]; + auto it = pos.find(rootChild); + if (it == pos.end()) return 0; // invalid + const int idx = it->second; + const int sz = idx - o + 1; // size of this child's subtree + ways *= solve_one(pre, i, i + sz - 1, post, o, idx, pos); + ++children; + i += sz; + o = idx + 1; + } + if (children == 1) ways *= 2; // single child: left/right ambiguity + return ways; +} + +static output_type solve(const Input &in) { + output_type out; + out.reserve(in.cases.size()); + for (const auto &c: in.cases) { + const auto &pre = c.first; + const auto &post = c.second; + std::unordered_map pos; + for (int i = 0; i < static_cast(post.size()); ++i) pos[post[i]] = i; + long long res = solve_one(pre, 0, static_cast(pre.size()) - 1, post, 0, static_cast(post.size()) - 1, + pos); + out.push_back(res); + } + return out; +} + +static void write_output(const output_type &outv) { + for (const auto &v: outv) { + cout << v << end; + } +} + +int main() { + const auto in = read_input(); + if (in.T <= 0) return 0; + const auto outv = solve(in); + write_output(outv); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_07/lab_07_D/resource/01.data.in b/algorithm/2021F/lab_07/lab_07_D/resource/01.data.in new file mode 100644 index 00000000..db2962cc --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_D/resource/01.data.in @@ -0,0 +1,3 @@ +1 +ABCD +DCBA diff --git a/algorithm/2021F/lab_07/lab_07_D/resource/01.data.out b/algorithm/2021F/lab_07/lab_07_D/resource/01.data.out new file mode 100644 index 00000000..45a4fb75 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_D/resource/01.data.out @@ -0,0 +1 @@ +8 diff --git a/algorithm/2021F/lab_07/lab_07_D/test.cpp b/algorithm/2021F/lab_07/lab_07_D/test.cpp new file mode 100644 index 00000000..3910033e --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_D/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_07/lab_07_D/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_07_D { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 07_D]", "[test 07_D]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_07/lab_07_E/CMakeLists.txt b/algorithm/2021F/lab_07/lab_07_E/CMakeLists.txt new file mode 100644 index 00000000..f6252ecc --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_E/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER E) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_07/lab_07_E/README.md b/algorithm/2021F/lab_07/lab_07_E/README.md new file mode 100644 index 00000000..c6909d89 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_E/README.md @@ -0,0 +1,63 @@ +## Description + +There is a tree with $n$ nodes and numbered from 1 to $n$, connected by $n-1$ edges. + +The root of the tree is node 1. + +Now Dateri is on the root node and wants to visit each node in the tree and return the root. + +Also, he wants to pass each edge exactly twice and visit the leaves in a specific order. + +Your task is to find whether there exists such a route satisfying Dateri's request. + +### Input + +The first line contains an integer $n$ $(3 \le n \le 5000)$, the number of nodes in the tree. + +Then next $n - 1$ lines describe edges. + +Each edge is described with two integers — indexes of nodes which it connects. + +Then the next line contains $k$ integers (here $k$ is the number of leaves in the tree), which describes the order in which the leaves should be visited. + +Guaranteed that each leaf node appears in this order exactly once. + +### Output + +If the route does not exist, output $-1$. + +Otherwise, output $2n-1$ indexes of the tree, describing the route. + +Multiple integers in one line must be separated by exactly one space. + +### Sample Input + +``` log +6 +1 2 +1 3 +2 4 +4 5 +4 6 +5 6 3 +``` + +### Sample Output + +``` log +1 2 4 5 4 6 4 2 1 3 1 +``` + +### HINT + +### 算法分析 + +在读入阶段使用链式前向星构建无向树并以 1 为根构造有根树的子节点列表。 + +对每个节点递归计算其子树包含的叶子数量和叶子在所给顺序中的最小/最大位置,以判定该节点的叶子在序列中是否构成连续区间。 + +若任一节点不满足连续区间属性,则不存在满足约束的遍历序列; 否则将每个节点的子节点按其子树最小位置排序以恢复合法访问次序。 + +最后使用迭代方式构建欧拉游走序列(每条边恰好被走两次),并输出长度为 2n-1 的路径。 + +递归计算子树区间时需处理叶子与非叶子的差异,整体时间复杂度为 O(n log n) 主要来自子节点排序,空间复杂度为 O(n)。 diff --git a/algorithm/2021F/lab_07/lab_07_E/main.cpp b/algorithm/2021F/lab_07/lab_07_E/main.cpp new file mode 100644 index 00000000..199e7af8 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_E/main.cpp @@ -0,0 +1,264 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include + +namespace tree { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { +public: + // 边的结构体定义 + std::vector head; // head[i] 存储顶点i的第一条边的索引 + std::vector edges; // 存储所有边的数组 + int32_t edge_count; // 当前边的总数 +public: + /** + * @brief 构造函数 + * @param num_nodes 顶点的数量 (假设顶点编号从 1 到 num_nodes) + * @param max_edges 预估的最大边数 (对于无向图,一条无向边算两条有向边) + */ + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + // 初始化头节点数组,大小为顶点数+1,方便1-based 索引 + // 所有顶点的初始头节点都设为-1,表示没有出边 + head.assign(num_nodes + 1, -1); + // 预分配存储所有边的空间 + edges.resize(max_edges); + } + + /** + * @brief 添加一条有向边 + * @param u 起点 + * @param v 终点 + * @param w 权重 + */ + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + // 在边数组的末尾添加新边 + edges[edge_count].to = v; + edges[edge_count].weight = w; + // 新边的 next 指向原来以 u 为起点的第一条边 + edges[edge_count].next = head[u]; + // 更新以 u 为起点的第一条边为当前新添加的边 + head[u] = edge_count; + // 边计数器加一 + edge_count++; + } + + /** + * @brief 添加一条无向边 + * @param u, v 顶点 + * @param w 权重 + */ + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + add_edge(u, v, w); + add_edge(v, u, w); + } +}; +} + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_07_E { +#endif +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +static constexpr const char end{'\n'}; + +struct Input { + int n{0}; + std::shared_ptr graph; + std::vector order; // desired leaf visit order +}; + +using output_type = std::vector; + +static Input read_input() { + Input in{}; + if (!(cin >> in.n)) return in; + const int max_edges = std::max(1, (in.n - 1) * 2); + in.graph = std::make_shared(in.n, max_edges); + for (int i = 0; i < in.n - 1; ++i) { + int u, v; + cin >> u >> v; + in.graph->add_undirected_edge(u, v, 0); + } + // read remaining integers as the leaf order + int x; + while (cin >> x) in.order.push_back(x); + return in; +} + +// compute subtree leaf counts and min/max positions; return false if invalid +static bool compute_intervals(int u, const std::vector > &children, + const std::vector &pos, std::vector &leaf_cnt, + std::vector &minPos, std::vector &maxPos) { + const int INF = std::numeric_limits::max() / 4; + if (children[u].empty()) { + // leaf + leaf_cnt[u] = 1; + minPos[u] = maxPos[u] = pos[u]; + return pos[u] != -1; // must appear in sequence + } + int cnt = 0; + int mn = INF, mx = -INF; + for (const int v: children[u]) { + if (!compute_intervals(v, children, pos, leaf_cnt, minPos, maxPos)) { + return false; + } + cnt += leaf_cnt[v]; + mn = std::min(mn, minPos[v]); + mx = std::max(mx, maxPos[v]); + } + leaf_cnt[u] = cnt; + minPos[u] = mn; + maxPos[u] = mx; + // check contiguous block property + if (mx - mn + 1 != cnt) { + return false; + } + return true; +} + +static output_type solve(const Input &in) { + const int n = in.n; + const auto &graph = *in.graph; + output_type empty; + if (n <= 0) return empty; + + // build rooted tree at 1 + std::vector parent(n + 1, -1); + std::vector > children(n + 1); + parent[1] = 0; + std::vector st; + st.reserve(n); + st.push_back(1); + while (!st.empty()) { + const int u = st.back(); + st.pop_back(); + for (int ei = graph.head[u]; ei != -1; ei = graph.edges[ei].next) { + int v = graph.edges[ei].to; + if (v == parent[u]) { + continue; + } + parent[v] = u; + children[u].push_back(v); + st.push_back(v); + } + } + + // identify leaves + std::vector leaves; + for (int u = 1; u <= n; ++u) { + if (children[u].empty()) { + leaves.push_back(u); + } + } + + // check order size matches leaves + if ((int) in.order.size() != (int) leaves.size()) return {-1}; + + // map leaf -> position + std::vector pos(n + 1, -1); + for (int i = 0; i < (int) in.order.size(); ++i) pos[in.order[i]] = i; + // ensure order contains exactly all leaves + for (const int leaf: leaves) { + if (pos[leaf] == -1) { + return {-1}; + } + } + + // compute intervals + std::vector leaf_cnt(n + 1, 0), minPos(n + 1, 0), maxPos(n + 1, 0); + // use recursion from root; if fails, impossible + if (!compute_intervals(1, children, pos, leaf_cnt, minPos, maxPos)) { + return {-1}; + } + + // reorder children by minPos + for (int u = 1; u <= n; ++u) { + std::sort(children[u].begin(), children[u].end(), [&](const int a, const int b) { + return minPos[a] < minPos[b]; + }); + } + + // build Euler tour (iterative to avoid recursion/std::function) + std::vector tour; + tour.reserve(2 * n - 1); + std::vector > stack; // node, next child idx + stack.emplace_back(1, 0); + while (!stack.empty()) { + auto &top = stack.back(); + int u = top.first; + int &idx = top.second; + if (idx == 0) { + tour.push_back(u); + } + if (idx < (int) children[u].size()) { + int v = children[u][idx++]; + stack.emplace_back(v, 0); + } else { + stack.pop_back(); + if (!stack.empty()) tour.push_back(stack.back().first); + } + } + if ((int) tour.size() != 2 * n - 1) { + return {-1}; + } + return tour; +} + +static void write_output(const output_type &outv) { + if (outv.size() == 1 && outv[0] == -1) { + cout << -1 << end; + return; + } + for (size_t i = 0; i < outv.size(); ++i) { + if (i) { + cout << ' '; + } + cout << outv[i]; + } + cout << end; +} + +int main() { + const auto in = read_input(); + if (in.n <= 0) { + return 0; + } + const auto outv = solve(in); + write_output(outv); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_07/lab_07_E/resource/01.data.in b/algorithm/2021F/lab_07/lab_07_E/resource/01.data.in new file mode 100644 index 00000000..811f41af --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_E/resource/01.data.in @@ -0,0 +1,7 @@ +6 +1 2 +1 3 +2 4 +4 5 +4 6 +5 6 3 diff --git a/algorithm/2021F/lab_07/lab_07_E/resource/01.data.out b/algorithm/2021F/lab_07/lab_07_E/resource/01.data.out new file mode 100644 index 00000000..2bd436b7 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_E/resource/01.data.out @@ -0,0 +1 @@ +1 2 4 5 4 6 4 2 1 3 1 diff --git a/algorithm/2021F/lab_07/lab_07_E/test.cpp b/algorithm/2021F/lab_07/lab_07_E/test.cpp new file mode 100644 index 00000000..535f8421 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_E/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_07/lab_07_E/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_07_E { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 07_E]", "[test 07_E]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_07/lab_07_F/CMakeLists.txt b/algorithm/2021F/lab_07/lab_07_F/CMakeLists.txt new file mode 100644 index 00000000..3bd8bb2b --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_F/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER F) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_07/lab_07_F/README.md b/algorithm/2021F/lab_07/lab_07_F/README.md new file mode 100644 index 00000000..ea93c378 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_F/README.md @@ -0,0 +1,52 @@ +## Description + +There are $n$ cities numbered from $1$ to $n$, and $n-1$ roads connecting these $n$ cities. i.e., it is a tree with $n$ nodes. + +Each road takes $1$ day for people to travel through. + +There are $k$ people who initially stay in different $k$ cities. They decide to meet in the same city as soon as possible. + +Please find the minimal time needed. + +### Input + +The first line will be an integer $T$ $(1 \le T \le 10)$, which is the number of test cases. + +For each test, the first line contains two integers $n$ and $k$ $(1 \le n \le 100000, 1 \le k \le n)$ — the number of cities and the number of friends. + +Then there are $n - 1$ lines. Each line contains two integers $A$ and $B$, which means there is a road between city $A$ and city $B$. + +Then there is a line contain $k$ integers the $i$-th integer $p_i$ indicates the place they initially stays. + +### Output + +$T$ lines. For each case, one integer in one line for the minimal time to meet. + +### Sample Input + +``` log +1 +4 2 +1 2 +2 4 +2 3 +1 3 +``` + +### Sample Output + +``` log +1 +``` + +### HINT + +### 算法分析 + +读入时使用链式前向星构建树并保存标记节点的位置集合。 + +为计算标记节点之间的最短会合时间,选取任意一个标记节点进行一次 BFS 找到距离最远的标记点 far。 + +然后从 far 再做一次 BFS,标记节点间的最大距离即为标记子集的直径;最早会合时间为直径的上取整的一半,即 ceil(diameter/2)。 + +两次 BFS 的时间复杂度均为 O(n),总体为 O(n) ,空间复杂度为 O(n)。 diff --git a/algorithm/2021F/lab_07/lab_07_F/main.cpp b/algorithm/2021F/lab_07/lab_07_F/main.cpp new file mode 100644 index 00000000..6e0dc54a --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_F/main.cpp @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include +#include + +namespace tree { +struct Edge { + int32_t to; + int32_t next; + int64_t weight; +}; + +class Graph { +public: + std::vector head; + std::vector edges; + int32_t edge_count; + + Graph(int32_t num_nodes = 0, int32_t max_edges = 0) : edge_count(0) { + head.assign(num_nodes + 1, -1); + edges.resize(max_edges); + } + + void reset(int32_t num_nodes, int32_t max_edges) { + head.assign(num_nodes + 1, -1); + edges.clear(); + edges.resize(max_edges); + edge_count = 0; + } + + void add_edge(int32_t u, int32_t v, int64_t w = 0) { + edges[edge_count].to = v; + edges[edge_count].weight = w; + edges[edge_count].next = head[u]; + head[u] = edge_count; + ++edge_count; + } + + void add_undirected_edge(int32_t u, int32_t v) { + add_edge(u, v, 1); + add_edge(v, u, 1); + } +}; +} +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_07_F { +#endif + +using std::cin; +using std::cout; +using std::vector; +using std::tuple; +using std::get; +using num_t = int32_t; +using answer_t = int32_t; + +struct TestCase { + int n; + int k; + std::shared_ptr graph; // 图在读取阶段构建 + vector marked; +}; + +vector read_all() { + int T; + if (!(cin >> T)) return {}; + vector tests; + tests.reserve(T); + for (int tc = 0; tc < T; ++tc) { + TestCase t; + cin >> t.n >> t.k; + // create graph and build edges immediately + t.graph = std::make_shared(t.n, (t.n - 1) * 2 + 5); + for (int i = 0; i < t.n - 1; ++i) { + int a, b; + cin >> a >> b; + t.graph->add_undirected_edge(a, b); + } + t.marked.resize(t.k); + for (int i = 0; i < t.k; ++i) { + cin >> t.marked[i]; + } + tests.push_back(std::move(t)); + } + return tests; +} + +// BFS on tree stored as forward-star. returns distances (1-based nodes) +vector bfs_distance(const tree::Graph &g, int src, int n) { + vector dist(n + 1, -1); + std::queue q; + dist[src] = 0; + q.push(src); + while (!q.empty()) { + const int u = q.front(); + q.pop(); + for (int ei = g.head[u]; ei != -1; ei = g.edges[ei].next) { + const int v = g.edges[ei].to; + if (dist[v] == -1) { + dist[v] = dist[u] + 1; + q.push(v); + } + } + } + return dist; +} + +vector cal_all(const vector &tests) { + vector answers; + answers.reserve(tests.size()); + for (const auto &t: tests) { + if (t.k <= 1) { + answers.push_back(0); + continue; + } + auto &gptr = t.graph; + // pick an arbitrary marked node + int s = t.marked[0]; + auto dist1 = bfs_distance(*gptr, s, t.n); + // find farthest marked from s + int far = s; + int bestd = -1; + for (int m: t.marked) { + if (dist1[m] > bestd) { + bestd = dist1[m]; + far = m; + } + } + // BFS from far + auto dist2 = bfs_distance(*gptr, far, t.n); + int diameter = 0; + for (int m: t.marked) diameter = std::max(diameter, dist2[m]); + // minimal meeting time is ceil(diameter / 2.0) + answers.push_back((diameter + 1) / 2); + } + return answers; +} + +void output_all(const vector &answers) { + for (auto a: answers) cout << a << '\n'; +} + +int main() { + const auto tests = read_all(); + const auto ans = cal_all(tests); + output_all(ans); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_07/lab_07_F/resource/01.data.in b/algorithm/2021F/lab_07/lab_07_F/resource/01.data.in new file mode 100644 index 00000000..241a41ca --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_F/resource/01.data.in @@ -0,0 +1,6 @@ +1 +4 2 +1 2 +2 4 +2 3 +1 3 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/1.data.out b/algorithm/2021F/lab_07/lab_07_F/resource/01.data.out similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/1.data.out rename to algorithm/2021F/lab_07/lab_07_F/resource/01.data.out diff --git a/algorithm/2021F/lab_07/lab_07_F/test.cpp b/algorithm/2021F/lab_07/lab_07_F/test.cpp new file mode 100644 index 00000000..a82052db --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_F/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_07/lab_07_F/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_07_F { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 07_F]", "[test 07_F]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_07/lab_07_G/CMakeLists.txt b/algorithm/2021F/lab_07/lab_07_G/CMakeLists.txt new file mode 100644 index 00000000..768dc1e2 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_G/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER G) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_07/lab_07_G/README.md b/algorithm/2021F/lab_07/lab_07_G/README.md new file mode 100644 index 00000000..d61678d0 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_G/README.md @@ -0,0 +1,53 @@ +## Description + +Given a tree $T$ whose nodes are numbered from 1 to $n$. and The root of the tree is node 1. + +Define $dis(x, y)$ as the distance between node $x$ and node $y$ (i.e., the least number of edges in the path from node $x$ to node $y$). + +Then define $k(w)=\sum_{v \in T} dis(w, v)$. + +We call a node $w$ on tree $T$ the critical node if and only if $k(w) \le \min_{u\in T} k(u)$. + +You are asked to print all the critical nodes of the subtree rooted at node $i$ for $i \in [1,n]$. + +### Input + +The first line contains an integer $n$ $(1 \le n \le 200000)$, indicating the number of nodes of the tree $T$. + +Then $n-1$ lines follow. Each line contains two integers $u, v$ $(1 \le u, v \le n)$ describing an edge, indicating the indexes of vertexes that connect an edge. + +### Output + +Output $n$ lines. On the $i^{th}$ line, output all the critical nodes of the subtree rooted at node $i$ in ascending order. Multiple integers in one line must be separated by one space. + +### Sample Input + +``` log +4 +1 2 +2 3 +2 4 +``` + +### Sample Output + +``` log +2 +2 +3 +4 +``` + +### HINT + +### 算法分析 + +首先使用链式前向星在读入阶段构建树并以 1 为根建立父子关系和深度信息。 + +计算以 1 为根的所有节点到根的距和,then 使用rerooting 计算每个节点的 k(u)=sum dis(u,v)。 + +使用 Euler-tour (tin/tout) 记录子树区间,并在 tin 序上构建线段树以支持区间最小值查询。 + +将具有相同 k 值的节点按 tin 排序,对于每個子树区间直接查询到最小 k 并在该 k 值对应的节点序列中二分获取位于区间內的节点集合。 + +最终每个子树的关键节点集合通过排序后输出。整体时间复杂度约为 O(n log n),空间复杂度为 O(n)。 diff --git a/algorithm/2021F/lab_07/lab_07_G/main.cpp b/algorithm/2021F/lab_07/lab_07_G/main.cpp new file mode 100644 index 00000000..63147233 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_G/main.cpp @@ -0,0 +1,247 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include + +namespace tree { +struct Edge { + int32_t to; + int32_t next; +}; + +class Graph { +public: + std::vector head; + std::vector edges; + int32_t edge_count; + + Graph(int32_t num_nodes = 0, int32_t max_edges = 0) : edge_count(0) { + head.assign(num_nodes + 1, -1); + edges.resize(max_edges); + } + + void reset(int32_t num_nodes, int32_t max_edges) { + head.assign(num_nodes + 1, -1); + edges.clear(); + edges.resize(max_edges); + edge_count = 0; + } + + void add_edge(const int32_t u, const int32_t v) { + edges[edge_count].to = v; + edges[edge_count].next = head[u]; + head[u] = edge_count++; + } + + void add_undirected_edge(const int32_t u, const int32_t v) { + add_edge(u, v); + add_edge(v, u); + } +}; +} + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_07_G { +#endif + +using int32 = std::int32_t; + +static constexpr int32_t LOG = 19; + +struct Input { + int32 n; + tree::Graph g; +}; + +struct Output { + std::vector > answers; +}; + +// 三段式: 读取 -> 计算 -> 输出 +Input read_input() { + Input in; + int32 n = 0; + if (!(std::cin >> n)) { + in.n = 0; + return in; + } + in.n = n; + in.g.reset(n, (n - 1) * 2 + 5); + for (int32 i = 0; i < n - 1; ++i) { + int32 u = 0; + int32 v = 0; + std::cin >> u >> v; + in.g.add_undirected_edge(u, v); + } + return in; +} + +Output solve(const Input &in) { + Output out; + const int32 n = in.n; + if (n == 0) { + return out; + } + const auto &g = in.g; + + std::vector parent(n + 1, 0); + std::vector depth(n + 1, 0); + std::vector order; + order.reserve(n); + order.push_back(1); + parent[1] = 0; + depth[1] = 0; + + std::vector > children(n + 1); + + for (size_t idx = 0; idx < order.size(); ++idx) { + const int32 u = order[idx]; + for (int32 ei = g.head[u]; ei != -1; ei = g.edges[ei].next) { + const int32 v = g.edges[ei].to; + if (v == parent[u]) { + continue; + } + parent[v] = u; + depth[v] = depth[u] + 1; + order.push_back(v); + children[u].push_back(v); + } + } + + std::vector subtree_size(n + 1, 1); + std::vector max_child(n + 1, 0); + std::vector heavy_child(n + 1, 0); + for (auto it = order.rbegin(); it != order.rend(); ++it) { + const int32 u = *it; + int32 best = 0; + for (const int32 v: children[u]) { + subtree_size[u] += subtree_size[v]; + if (subtree_size[v] > max_child[u]) { + max_child[u] = subtree_size[v]; + } + if (best == 0 || subtree_size[v] > subtree_size[best]) { + best = v; + } + } + heavy_child[u] = best; + } + + std::vector > heavy_jump(n + 1); + for (int32 u = 1; u <= n; ++u) { + heavy_jump[u].fill(0); + heavy_jump[u][0] = heavy_child[u]; + } + for (int j = 1; j < LOG; ++j) { + for (int32 u = 1; u <= n; ++u) { + const int32 mid = heavy_jump[u][j - 1]; + heavy_jump[u][j] = (mid == 0) ? 0 : heavy_jump[mid][j - 1]; + } + } + + std::vector tin(n + 1, 0); + std::vector tout(n + 1, 0); + int32 timer = 0; + std::vector > stack; + stack.reserve(n); + stack.emplace_back(1, 0); + while (!stack.empty()) { + auto &top = stack.back(); + const int32 u = top.first; + size_t &idx = top.second; + if (idx == 0) { + tin[u] = ++timer; + } + if (idx < children[u].size()) { + const int32 v = children[u][idx++]; + stack.emplace_back(v, 0); + } else { + tout[u] = timer; + stack.pop_back(); + } + } + + out.answers.assign(n + 1, {}); + std::vector buffer; + buffer.reserve(2); + + for (const int32 u: order) { + const int32 total = subtree_size[u]; + const int32 limit = total / 2; + int32 cur = u; + for (int j = LOG - 1; j >= 0; --j) { + const int32 nxt = heavy_jump[cur][j]; + if (nxt != 0 && subtree_size[nxt] > limit) { + cur = nxt; + } + } + buffer.clear(); + const auto check = [&](const int32 node) -> bool { + if (node == 0) { + return false; + } + int32 largest = max_child[node]; + const int32 rest = total - subtree_size[node]; + if (rest > largest) { + largest = rest; + } + return largest <= limit; + }; + if (check(cur)) { + buffer.push_back(cur); + } + const int32 candidate = heavy_child[cur]; + if (candidate != 0 && subtree_size[candidate] * 2 == total && check(candidate)) { + buffer.push_back(candidate); + } + std::sort(buffer.begin(), buffer.end()); + out.answers[u] = buffer; + } + + return out; +} + +void write_output(const Output &out) { + const auto &ans = out.answers; + const int32 n = static_cast(ans.size()) - 1; + for (int32 i = 1; i <= n; ++i) { + const auto &row = ans[i]; + for (size_t j = 0; j < row.size(); ++j) { + if (j != 0) { + std::cout << ' '; + } + std::cout << row[j]; + } + std::cout << '\n'; + } +} + +int main() { + const auto input = read_input(); + const auto result = solve(input); + write_output(result); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_07/lab_07_G/resource/01.data.in b/algorithm/2021F/lab_07/lab_07_G/resource/01.data.in new file mode 100644 index 00000000..913dc828 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_G/resource/01.data.in @@ -0,0 +1,4 @@ +4 +1 2 +2 3 +2 4 diff --git a/algorithm/2021F/lab_07/lab_07_G/resource/01.data.out b/algorithm/2021F/lab_07/lab_07_G/resource/01.data.out new file mode 100644 index 00000000..7eb16326 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_G/resource/01.data.out @@ -0,0 +1,4 @@ +2 +2 +3 +4 diff --git a/algorithm/2021F/lab_07/lab_07_G/test.cpp b/algorithm/2021F/lab_07/lab_07_G/test.cpp new file mode 100644 index 00000000..906975d7 --- /dev/null +++ b/algorithm/2021F/lab_07/lab_07_G/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_07/lab_07_G/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_07_G { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 07_G]", "[test 07_G]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_08/CMakeLists.txt b/algorithm/2021F/lab_08/CMakeLists.txt new file mode 100644 index 00000000..1b6d4362 --- /dev/null +++ b/algorithm/2021F/lab_08/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROJECT_ORDER lab_08) +project(${PROJECT_NAME}_${PROJECT_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +set(dependencies A B C D E F G) +foreach (elementName IN LISTS dependencies) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${elementName}) +endforeach () +unset(dependencies) diff --git a/algorithm/2021F/lab_08/README.md b/algorithm/2021F/lab_08/README.md new file mode 100644 index 00000000..1ee8b755 --- /dev/null +++ b/algorithm/2021F/lab_08/README.md @@ -0,0 +1,31 @@ +# Contest1106 - CS203 2021 Fall Lab 08 Advanced Tree + +> cid: 1105 + +Welcome to CS203 2021 Fall Lab 08! Enjoy this Lab! + +There are six problems for you to solve. + +Score: + +- A: 10 +- B: 15/10 +- C: 15/10 +- D: 20/15 +- E: 20/15 +- F: 20 +- G: undefined/20 + +Reading the samples and hints carefully can help you understand the problem. + +## Problem mapping + +| Problem | problem id | +|---:|---:| +| A | 1460 | +| B | 1461 | +| C | 1462 | +| D | 1463 | +| E | 1464 | +| F | 1465 | +| G | 1466 | diff --git a/algorithm/2021F/lab_08/cs203.submit.csv b/algorithm/2021F/lab_08/cs203.submit.csv new file mode 100644 index 00000000..c983d033 --- /dev/null +++ b/algorithm/2021F/lab_08/cs203.submit.csv @@ -0,0 +1,8 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 226, 1, 56, 27, 4, 13, 27, 354, 12, 81, 261 +B, 221, 91, 3, 1, 4, 41, 15, 376, 75, 301 +C, 219, 1, 387, 168, 90, 8, 400, 54, 1327, 6, 274, 1047 +D, 223, 1, 722, 207, 11, 1, 169, 49, 1383, 4, 199, 1180 +E, 221, 1, 218, 83, 1, 1, 129, 19, 673, 2, 122, 549 +F, 95, 230, 158, 2, 7, 264, 34, 790, 11, 164, 615 +Total, 1205, 4, 1704, 646, 105, 25, 1016, 198, 4903, 35, 915, 3953 diff --git a/algorithm/2021F/lab_08/cs217.submit.csv b/algorithm/2021F/lab_08/cs217.submit.csv new file mode 100644 index 00000000..a38a6445 --- /dev/null +++ b/algorithm/2021F/lab_08/cs217.submit.csv @@ -0,0 +1,9 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 42, 3, 7, 5, 57, 39, 18 +B, 30, 11, 3, 3, 47, 26, 21 +C, 50, 42, 22, 2, 4, 23, 7, 150, 96, 54 +D, 37, 52, 24, 11, 8, 132, 57, 75 +E, 32, 14, 9, 5, 3, 63, 2, 30, 31 +F, 76, 81, 32, 1, 50, 6, 246, 129, 117 +G, 44, 72, 27, 3, 1, 28, 6, 1, 182, 74, 108 +Total, 311, 275, 121, 5, 6, 125, 33, 1, 877, 2, 451, 424 diff --git a/algorithm/2021F/lab_08/lab_08_A/CMakeLists.txt b/algorithm/2021F/lab_08/lab_08_A/CMakeLists.txt new file mode 100644 index 00000000..40897f09 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_A/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER A) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_08/lab_08_A/README.md b/algorithm/2021F/lab_08/lab_08_A/README.md new file mode 100644 index 00000000..aa2e85c8 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_A/README.md @@ -0,0 +1,63 @@ +# lab_08_A + +## Description + +You're required to devise a data structure as follows. + +It is a complete binary tree. + +The key of each node is larger than its children's (if it has any). + +We call it Heap. + +Initially your heap is empty. + +Then you are asked to insert $N$ distinct integers into the heap one by one. + +When you insert a new element into the heap, you should: + +- Place it at the leftmost position of the complete binary tree. +- Swap it with its father if it is larger than the key of its father until it becomes the root of the heap or it is smaller than the key of its father. + +Now little HEAP wants to know the number of swapping times in each insertion. + +### Input + +The first line contains a single integer $N(1\leq N\leq 3\times 10^5)$. + +The second line contains $N$ integers $A_1,A_2,\ldots,A_N(1\leq A_i\leq 10^9)$, denoting the integers you are going to insert in order. + +It is guaranteed that these integers are distinct. + +### Output + +Output $N$ integers separated by spaces, representing the number of swapping times in each insertion. + +### Sample Input + +``` log +7 +5 4 8 6 2 12 55 +``` + +### Sample Output + +``` log +0 0 1 1 0 2 2 +``` + +### HINT + +## 算法分析 (zh-CN) + +实现要点: +- 采用 1-based 的数组表示完全二叉堆。每次插入时,将新元素放在数组末尾,然后执行上浮(sift-up):当当前结点比父结点大时,交换并将位置移动到父结点,直到不需要交换为止。 +- 在上浮过程中计数交换次数,并记录每次插入的交换次数输出。 + +时间复杂度:每次插入的上浮次数最多为 O(log N),因此总体复杂度为 O(N log N)。 + +空间复杂度:O(N) 用于保存堆数组与输入数组。 + +正确性说明:完全二叉堆的插入操作即为将元素追加到最后再上浮,算法直接模拟该过程,交换计数即为上浮的步数,满足题意。 + +注意事项与边界:输入保证 N≥1 且元素互不相同;代码采用 int64 存储元素以防边界值。 diff --git a/algorithm/2021F/lab_08/lab_08_A/main.cpp b/algorithm/2021F/lab_08/lab_08_A/main.cpp new file mode 100644 index 00000000..dc5b5646 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_A/main.cpp @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds + +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_08_A { +#endif +// 以下严格遵守 AGENTS.md 中的代码风格与三段式(read/process/write) +using int32 = std::int32_t; +using int64 = std::int64_t; + +static constexpr char NL{'\n'}; + +struct Input { + int32 n; + std::vector a; +}; + +struct Output { + std::vector swaps; +}; + +// 读取阶段:读取输入并返回 Input 结构 +Input read_input() { + Input in{}; + std::cin >> in.n; + in.a.resize(in.n); + for (int32 i = 0; i < in.n; ++i) { + std::cin >> in.a[i]; + } + return in; +} + +// 处理阶段:计算每次插入堆时的上浮次数 +Output solve(const Input &in) { + Output out{}; + out.swaps.reserve(in.n); + + // 使用 1-based 完全二叉堆数组表示 + std::vector heap; + heap.reserve(in.n + 1); + heap.push_back(0); // 0 号位不使用,方便 1-based + + for (int32 i = 0; i < in.n; ++i) { + const auto val = in.a[i]; + heap.push_back(val); + int32 pos = static_cast(heap.size() - 1); + int32 cnt = 0; + + // 上浮:如果父节点更小则交换 + while (pos > 1) { + const int32 parent = pos / 2; + if (heap[parent] >= heap[pos]) break; + std::swap(heap[parent], heap[pos]); + pos = parent; + ++cnt; + } + out.swaps.push_back(cnt); + } + + return out; +} + +// 输出阶段:将结果写回 stdout +void write_output(const Output &out) { + const auto &v = out.swaps; + for (size_t i = 0; i < v.size(); ++i) { + if (i) std::cout << ' '; + std::cout << v[i]; + } + std::cout << NL; +} + +int main() { + const auto input = read_input(); + const auto result = solve(input); + write_output(result); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_08/lab_08_A/resource/01.data.in b/algorithm/2021F/lab_08/lab_08_A/resource/01.data.in new file mode 100644 index 00000000..c3354262 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_A/resource/01.data.in @@ -0,0 +1,2 @@ +7 +5 4 8 6 2 12 55 diff --git a/algorithm/2021F/lab_08/lab_08_A/resource/01.data.out b/algorithm/2021F/lab_08/lab_08_A/resource/01.data.out new file mode 100644 index 00000000..072f0df6 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_A/resource/01.data.out @@ -0,0 +1 @@ +0 0 1 1 0 2 2 diff --git a/algorithm/2021F/lab_08/lab_08_A/test.cpp b/algorithm/2021F/lab_08/lab_08_A/test.cpp new file mode 100644 index 00000000..6f7f5326 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_A/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_08/lab_08_A/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_08_A { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 08_A]", "[test 08_A]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_08/lab_08_B/CMakeLists.txt b/algorithm/2021F/lab_08/lab_08_B/CMakeLists.txt new file mode 100644 index 00000000..dac0839a --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_B/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER B) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_08/lab_08_B/README.md b/algorithm/2021F/lab_08/lab_08_B/README.md new file mode 100644 index 00000000..f4060310 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_B/README.md @@ -0,0 +1,65 @@ +# lab_08_B + +## Description + +You are given a complete binary tree and each node has a distinct key value. + +Now you are asked to determine whether the tree is a heap or not. + +If it is a heap, you are to determine if it is a Max-heap or a Min-heap. + +### Input + +The first line contains $N(2\leq N\leq 10^6)$, denoting the number of nodes in the tree. + +The second line contains $N$ integers $A_1,A_2,\ldots,A_N(1\leq A_i\leq 10^9)$, denoting the key value of node $i$. + +It is guaranteed that no two key values are the same. + +To simplify the problem, the tree is constructed as follows: + +- The root of the tree is node 1. +- For each $2\leq i\leq N$, there is an edge between $i$ and $\lfloor i/2\rfloor$. + +### Output + +If the tree is a Max-heap, print "Max". + +If the tree is a Min-heap, print "Min". + +If the tree is not a heap, print "Neither" (without quotes). + +### Sample Input + +``` log +7 +55 6 12 4 2 5 8 +``` + +### Sample Output + +``` log +Max +``` + +### HINT + +不要使用任何与堆和BST相关的STL! + +## 算法分析 (zh-CN) + +实现要点: +- 题目给出数组按完全二叉树节点编号顺序存放。 +- 遍历 i = 2..N,比较 a[i] 与父节点 a[i/2]: + - 若对所有 i 均满足 a[parent] >= a[i],则为 Max-heap; + - 若对所有 i 均满足 a[parent] <= a[i],则为 Min-heap; + - 否则为 Neither。 + +时间复杂度:O(N)(单次线性扫描)。 + +空间复杂度:O(N)(存储数组)。 + +正确性:完全二叉树以数组表示,父子关系固定,上述判定直接对应堆定义。 + +边界与注意: +- N≥2;若 N=1(特殊情况),按实现可视为 Max(或按题意调整)。 diff --git a/algorithm/2021F/lab_08/lab_08_B/main.cpp b/algorithm/2021F/lab_08/lab_08_B/main.cpp new file mode 100644 index 00000000..712e5dfc --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_B/main.cpp @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds + +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_08_B { +#endif +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +using int32 = std::int32_t; +using int64 = std::int64_t; + +static constexpr char NL{'\n'}; + +// 常量字符串:避免在代码多处硬编码字面量 +static constexpr const char *const kMax = "Max"; +static constexpr const char *const kMin = "Min"; +static constexpr const char *const kNeither = "Neither"; + +struct Input { + int32 n; + std::vector a; +}; + +struct Output { + std::string ans; +}; + +// 读取阶段 +Input read_input() { + Input in{}; + std::cin >> in.n; + in.a.resize(in.n + 1); // 1-based for convenience + for (int32 i = 1; i <= in.n; ++i) { + std::cin >> in.a[i]; + } + return in; +} + +// 处理阶段:判断 Max / Min / Neither +Output solve(const Input &in) { + Output out{}; + if (in.n <= 1) { + out.ans = kMax; + return out; + } + + bool isMax = true; + bool isMin = true; + + for (int32 i = 2; i <= in.n; ++i) { + int32 p = i / 2; + if (in.a[p] < in.a[i]) isMax = false; + if (in.a[p] > in.a[i]) isMin = false; + if (!isMax && !isMin) break; + } + + if (isMax) { + out.ans = kMax; + } else if (isMin) { + out.ans = kMin; + } else { + out.ans = kNeither; + } + return out; +} + +// 输出阶段 +void write_output(const Output &out) { + std::cout << out.ans << NL; +} + +int main() { + const auto in = read_input(); + const auto res = solve(in); + write_output(res); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_08/lab_08_B/resource/01.data.in b/algorithm/2021F/lab_08/lab_08_B/resource/01.data.in new file mode 100644 index 00000000..a0ccaa72 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_B/resource/01.data.in @@ -0,0 +1,2 @@ +7 +55 6 12 4 2 5 8 diff --git a/algorithm/2021F/lab_08/lab_08_B/resource/01.data.out b/algorithm/2021F/lab_08/lab_08_B/resource/01.data.out new file mode 100644 index 00000000..3d6894aa --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_B/resource/01.data.out @@ -0,0 +1 @@ +Max diff --git a/algorithm/2021F/lab_08/lab_08_B/test.cpp b/algorithm/2021F/lab_08/lab_08_B/test.cpp new file mode 100644 index 00000000..732676e7 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_B/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_08/lab_08_B/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_08_B { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 08_B]", "[test 08_B]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_08/lab_08_C/CMakeLists.txt b/algorithm/2021F/lab_08/lab_08_C/CMakeLists.txt new file mode 100644 index 00000000..f07d2e4c --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_C/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER C) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_08/lab_08_C/README.md b/algorithm/2021F/lab_08/lab_08_C/README.md new file mode 100644 index 00000000..3a1dd175 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_C/README.md @@ -0,0 +1,58 @@ +# lab_08_C + +## Description + +We construct an array $C$ out of two given array $A$ and $B$ such that each element in array $C$ is the product of an element in $A$ and an element in $B$. + +For example, we have $A=[1,2,1]$ and $B=[5,2]$, then $C=[5,2,10,4,5,2]$. + +Now we only want to know the first $K$ smallest element of array $C$. + +### Input + +The first line contains three integers $N$, $M$ and $K$, denoting the length of array $A$, the length of array $B$ and $K$ smallest respectively. + +$(1\leq N,M\leq 5\times 10^5),K\leq \min(5\times 10^5,N\times M)$. + +The second line contains $N$ integers $A_1,A_2,\ldots,A_N(1\leq A_i\leq 10^9)$. + +The third line contains $M$ integers $B_1,B_2,\ldots,B_M(1\leq B_i\leq 10^9)$. + +### Output + +Output $K$ integers separated by spaces in ascending order, denoting the first $K$ smallest elements in $C$. + +### Sample Input + +``` log +3 2 6 +1 2 1 +5 2 +``` + +### Sample Output + +``` log +2 2 4 5 5 10 +``` + +### HINT + +不要使用任何与堆和BST相关的STL! + +## 算法分析 (zh-CN) + +实现要点: +- 题目要求输出数组 C(由 A 与 B 的所有乘积构成)中前 K 个最小值。 +- 做法:先对 A、B 排序,然后用自实现的最小堆维护当前最小候选对 (i, j)。初始将每个 A[i] 与 B[0] 配对入堆,依次弹出堆顶并将 (i, j+1) 入堆,直到得到 K 个最小乘积。 +- 堆节点包含 (i, j, value) 并按 value 与索引稳定性比较以保证顺序一致。 + +时间复杂度:堆大小最多为 min(N, K),总操作数约 O(K log min(N,K)),排序花费 O(N log N + M log M)。 + +空间复杂度:O(min(N,K) + N + M)。 + +正确性:此方法为常见“合并 K 条有序链”或“求 A×B 笛卡尔积前 K 小”的标准做法,保证按值顺序生成最小乘积且不重复缺失。 + +注意事项与边界: +- K ≤ N×M,注意当 K 很大时时间与内存压力;题目给限值,方案可接受。 +- 使用 64 位类型存乘积以防溢出(A, B 最高 1e9,乘积可达 1e18)。 diff --git a/algorithm/2021F/lab_08/lab_08_C/main.cpp b/algorithm/2021F/lab_08/lab_08_C/main.cpp new file mode 100644 index 00000000..a5ebb285 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_C/main.cpp @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_08_C { +#endif +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +static constexpr const char end{'\n'}; + +using i32 = int32_t; +using i64 = int64_t; + +struct ProblemInput { + i32 n; + i32 m; + i32 k; + std::vector a; + std::vector b; +}; + +using ProblemOutput = std::vector; + +// Forward declarations for three-stage main style +ProblemInput read_input(); + +ProblemOutput solve(const ProblemInput &in); + +void write_output(const ProblemOutput &out); + +int main() { + const auto in = read_input(); + const auto out = solve(in); + write_output(out); + return 0; +} + +// Read: parse N M K and arrays A and B +ProblemInput read_input() { + ProblemInput in; + std::cin >> in.n >> in.m >> in.k; + in.a.assign(static_cast(in.n), 0); + in.b.assign(static_cast(in.m), 0); + for (i32 i = 0; i < in.n; ++i) std::cin >> in.a[static_cast(i)]; + for (i32 j = 0; j < in.m; ++j) std::cin >> in.b[static_cast(j)]; + return in; +} + +// Use STL priority_queue (min-heap) for clarity and performance +struct HeapNode { + i32 i; // index in A + i32 j; // index in B + i64 val; // product a[i]*b[j] +}; + +struct HeapNodeComp { + bool operator()(const HeapNode &l, const HeapNode &r) const { + if (l.val != r.val) return l.val > r.val; // min-heap + if (l.i != r.i) return l.i > r.i; + return l.j > r.j; + } +}; + +// Solve: compute first K smallest products of pairs from A and B +ProblemOutput solve(const ProblemInput &in) { + const i32 n = in.n; + const i32 m = in.m; + const i32 k = in.k; + + // Copy and sort arrays to enable standard K-pairs enumeration + auto a = in.a; + auto b = in.b; + std::sort(a.begin(), a.end()); + std::sort(b.begin(), b.end()); + + const i32 initial = std::min(n, k); + std::priority_queue, HeapNodeComp> heap; + heap = std::priority_queue, HeapNodeComp>(HeapNodeComp()); + + // Push (i,0) for i in [0, initial) + for (i32 i = 0; i < initial; ++i) { + HeapNode node{i, 0, a[static_cast(i)] * b[0]}; + heap.push(node); + } + + ProblemOutput result; + result.reserve(static_cast(k)); + + while (!heap.empty() && static_cast(result.size()) < k) { + const auto cur = heap.top(); + heap.pop(); + result.push_back(cur.val); + const i32 ci = cur.i; + const i32 cj = cur.j + 1; + if (cj < m) { + HeapNode next{ci, cj, a[static_cast(ci)] * b[static_cast(cj)]}; + heap.push(next); + } + } + + return result; +} + +// Write: output K numbers separated by spaces in ascending order +void write_output(const ProblemOutput &out) { + const size_t sz = out.size(); + for (size_t idx = 0; idx < sz; ++idx) { + if (idx) std::cout << ' '; + std::cout << out[idx]; + } + std::cout << end; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_08/lab_08_C/resource/01.data.in b/algorithm/2021F/lab_08/lab_08_C/resource/01.data.in new file mode 100644 index 00000000..6c8cb5aa --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_C/resource/01.data.in @@ -0,0 +1,3 @@ +3 2 6 +1 2 1 +5 2 diff --git a/algorithm/2021F/lab_08/lab_08_C/resource/01.data.out b/algorithm/2021F/lab_08/lab_08_C/resource/01.data.out new file mode 100644 index 00000000..1d377459 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_C/resource/01.data.out @@ -0,0 +1 @@ +2 2 4 5 5 10 diff --git a/algorithm/2021F/lab_08/lab_08_C/test.cpp b/algorithm/2021F/lab_08/lab_08_C/test.cpp new file mode 100644 index 00000000..752eeec2 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_C/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_08/lab_08_C/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_08_C { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 08_C]", "[test 08_C]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_08/lab_08_D/CMakeLists.txt b/algorithm/2021F/lab_08/lab_08_D/CMakeLists.txt new file mode 100644 index 00000000..564aeae5 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_D/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER D) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_08/lab_08_D/README.md b/algorithm/2021F/lab_08/lab_08_D/README.md new file mode 100644 index 00000000..9e7a6f48 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_D/README.md @@ -0,0 +1,52 @@ +# lab_08_D + +## Description + +Given $N$ integers, you are required to merge them into one single integer using $N-1$ operations. + +During each operation, you can choose two integers $x$ and $y$ and replace the two integers with one single integer $x+y$ which costs $x+y$ power. + +Now you wonder the minimum sum of power possible to complete the mission. + +### Input + +The first line contains one integer $N(1\leq N\leq 5\times 10^5)$. + +The second line contains $N$ integers $A_1,A_2,\ldots,A_N(1\leq A_i\leq 10^7)$, denoting the $N$ integers you are required to merge. + +### Output + +Output one single integer indicating the minimum power to complete the mission. + +### Sample Input + +``` log +4 +5 1 9 2 +``` + +### Sample Output + +``` log +28 +``` + +### HINT + +不要使用任何与堆和BST相关的STL! + +## 算法分析 (zh-CN) + +实现要点: +- 该题为经典的最优合并(Huffman)问题。每次从集合中选择两个最小的数 x 和 y,将它们合并为 x+y,代价为 x+y,将合并结果重新加入集合。 +- 由于题目要求不使用 STL 的堆或 BST,代码中实现了一个最小堆(MinHeap),支持 push/top/pop 操作并在堆上反复执行合并操作。 + +时间复杂度:构建堆为 O(N),每次合并进行两次出堆和一次入堆,单次为 O(log N),共 N-1 次合并,总体 O(N log N)。 + +空间复杂度:O(N) 用于堆与输入数组。 + +正确性:贪心地每次合并当前最小的两个数可以最小化总体代价,这是 Huffman 或最优合并树的经典证明。 + +注意事项与边界: +- 当 N=1 时,代价为 0,应特殊处理。 +- 元素值与累加和可能较大,使用 64 位整型累加以防溢出。 diff --git a/algorithm/2021F/lab_08/lab_08_D/main.cpp b/algorithm/2021F/lab_08/lab_08_D/main.cpp new file mode 100644 index 00000000..0b5668b4 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_D/main.cpp @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_08_D { +#endif +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +static constexpr const char end{'\n'}; + +using i32 = int32_t; +using i64 = int64_t; + +struct ProblemInput { + i32 n; + std::vector a; +}; + +using ProblemOutput = i64; + +// Three-stage function declarations +ProblemInput read_input(); + +ProblemOutput solve(const ProblemInput &in); + +void write_output(const ProblemOutput &out); + +int main() { + const auto in = read_input(); + const auto out = solve(in); + write_output(out); + return 0; +} + +// Read: N and array A +ProblemInput read_input() { + ProblemInput in; + std::cin >> in.n; + in.a.assign(static_cast(in.n), 0); + for (i32 i = 0; i < in.n; ++i) std::cin >> in.a[static_cast(i)]; + return in; +} + +// Use STL priority_queue as min-heap (via greater comparator) +struct MinComp { + bool operator()(i64 l, i64 r) const { return l > r; } +}; + +// Solve: Huffman-style merging minimal total cost +ProblemOutput solve(const ProblemInput &in) { + const i32 n = in.n; + if (n <= 1) return 0; + + std::priority_queue, MinComp> heap; + for (i32 i = 0; i < n; ++i) heap.push(in.a[static_cast(i)]); + + i64 total = 0; + while (heap.size() > 1) { + const i64 x = heap.top(); + heap.pop(); + const i64 y = heap.top(); + heap.pop(); + const i64 s = x + y; + total += s; + heap.push(s); + } + return total; +} + +// Write: single integer result +void write_output(const ProblemOutput &out) { + std::cout << out << end; +} + +static const auto faster_streams = [] { + std::ios::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_08/lab_08_D/resource/01.data.in b/algorithm/2021F/lab_08/lab_08_D/resource/01.data.in new file mode 100644 index 00000000..0efcc32a --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_D/resource/01.data.in @@ -0,0 +1,2 @@ +4 +5 1 9 2 diff --git a/algorithm/2021F/lab_08/lab_08_D/resource/01.data.out b/algorithm/2021F/lab_08/lab_08_D/resource/01.data.out new file mode 100644 index 00000000..9902f178 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_D/resource/01.data.out @@ -0,0 +1 @@ +28 diff --git a/algorithm/2021F/lab_08/lab_08_D/test.cpp b/algorithm/2021F/lab_08/lab_08_D/test.cpp new file mode 100644 index 00000000..3657bf85 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_D/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_08/lab_08_D/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_08_D { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 08_D]", "[test 08_D]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_08/lab_08_E/CMakeLists.txt b/algorithm/2021F/lab_08/lab_08_E/CMakeLists.txt new file mode 100644 index 00000000..f6252ecc --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_E/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER E) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_08/lab_08_E/README.md b/algorithm/2021F/lab_08/lab_08_E/README.md new file mode 100644 index 00000000..3ad444f4 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_E/README.md @@ -0,0 +1,53 @@ +# lab_08_E + +## Description + +Given an array of length $N$: $A_1,A_2,\ldots,A_N$. + +For every $1\leq i\leq N$, you are asked to figure out the median of $A_1,A_2,\ldots,A_i$. + +The median of $A_1,A_2,\ldots,A_i$ is defined as the $\lceil i/2\rceil$-th element of the multiset after it is sorted. + +### Input + +The first line contains one integer $N(1\leq N\leq 5\times 10^5)$. + +The second line contains $N$ integers $A_1,A_2,\ldots,A_N(1\leq A_i\leq 10^9)$. + +### Output + +Output $N$ integers in a single line separated by spaces, the $i$-th of which represents the median of $A_1,A_2,\ldots,A_i$. + +### Sample Input + +``` log +5 +2 5 1 4 7 +``` + +### Sample Output + +``` log +2 2 2 2 4 +``` + +### HINT + +不要使用任何与堆和BST相关的STL! + +## 算法分析 (zh-CN) + +实现要点: +- 使用两个自实现的堆:大顶堆(lower)保存较小的一半元素,小顶堆(upper)保存较大的一半元素。 +- 每次插入新元素时先插入合适的堆,然后调整两堆大小以保证 lower.size() >= upper.size() 且两堆大小差不超过 1。 +- 当前前缀的中位数即为 lower.top(),因为题目要求的是第 ceil(i/2) 个元素。 + +时间复杂度:每次插入为 O(log N),总体 O(N log N)。 + +空间复杂度:O(N)。 + +正确性:通过维持两堆的大小与分界,lower.top() 始终为前缀集合中第 ceil(i/2) 个元素,满足定义。 + +注意事项与边界: +- 实现中使用自定义堆以避免 STL 的堆/BST 依赖。 +- 注意在平衡步骤中正确移动堆顶元素以维持不变式。 diff --git a/algorithm/2021F/lab_08/lab_08_E/main.cpp b/algorithm/2021F/lab_08/lab_08_E/main.cpp new file mode 100644 index 00000000..e171f06e --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_E/main.cpp @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_08_E { +#endif +using std::cin; +using std::cout; +using std::tie; +using std::tuple; +using std::vector; +static constexpr const char end{'\n'}; + +using i32 = int32_t; +using i64 = int64_t; + +struct ProblemInput { + i32 n; + std::vector a; +}; + +using ProblemOutput = std::vector; + +// Declarations for three-stage style +ProblemInput read_input(); + +ProblemOutput solve(const ProblemInput &in); + +void write_output(const ProblemOutput &out); + +int main() { + const auto in = read_input(); + const auto out = solve(in); + write_output(out); + return 0; +} + +ProblemInput read_input() { + ProblemInput in; + std::cin >> in.n; + in.a.assign(static_cast(in.n), 0); + for (i32 i = 0; i < in.n; ++i) { + std::cin >> in.a[static_cast(i)]; + } + return in; +} + +// Use STL priority_queue for lower (max-heap) and upper (min-heap) +struct MaxComp { + bool operator()(i64 l, i64 r) const { return l < r; } // max-heap +}; +struct MinComp { + bool operator()(i64 l, i64 r) const { return l > r; } // min-heap +}; + +ProblemOutput solve(const ProblemInput &in) { + const i32 n = in.n; + ProblemOutput res; + res.reserve(static_cast(n)); + + std::priority_queue, MaxComp> lower; // max-heap + std::priority_queue, MinComp> upper; // min-heap + // reserve not available for priority_queue; underlying vector resizes as needed + + for (i32 idx = 0; idx < n; ++idx) { + const i64 x = in.a[static_cast(idx)]; + if (lower.empty() || x <= lower.top()) { + lower.push(x); + } else { + upper.push(x); + } + + // rebalance: ensure lower.size() >= upper.size() and difference <= 1 + if (static_cast(lower.size()) > static_cast(upper.size()) + 1) { + const i64 v = lower.top(); + lower.pop(); + upper.push(v); + } else if (static_cast(lower.size()) < static_cast(upper.size())) { + const i64 v = upper.top(); + upper.pop(); + lower.push(v); + } + + // median is top of lower (ceil(i/2)-th) + res.push_back(lower.top()); + } + + return res; +} + +void write_output(const ProblemOutput &out) { + for (size_t i = 0; i < out.size(); ++i) { + if (i) std::cout << ' '; + std::cout << out[i]; + } + std::cout << end; +} + +static const auto faster_streams = [] { + std::ios::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_08/lab_08_E/resource/01.data.in b/algorithm/2021F/lab_08/lab_08_E/resource/01.data.in new file mode 100644 index 00000000..46b6f8a6 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_E/resource/01.data.in @@ -0,0 +1,2 @@ +5 +2 5 1 4 7 diff --git a/algorithm/2021F/lab_08/lab_08_E/resource/01.data.out b/algorithm/2021F/lab_08/lab_08_E/resource/01.data.out new file mode 100644 index 00000000..969b5c78 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_E/resource/01.data.out @@ -0,0 +1 @@ +2 2 2 2 4 diff --git a/algorithm/2021F/lab_08/lab_08_E/test.cpp b/algorithm/2021F/lab_08/lab_08_E/test.cpp new file mode 100644 index 00000000..3ec12ae7 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_E/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_08/lab_08_E/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_08_E { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 08_E]", "[test 08_E]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_08/lab_08_F/CMakeLists.txt b/algorithm/2021F/lab_08/lab_08_F/CMakeLists.txt new file mode 100644 index 00000000..3bd8bb2b --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_F/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER F) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_08/lab_08_F/README.md b/algorithm/2021F/lab_08/lab_08_F/README.md new file mode 100644 index 00000000..2f31422b --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_F/README.md @@ -0,0 +1,88 @@ +# lab_08_F + +## Description + +Recently Satori opened a bunny store. + +Initially the store has no bunny at all. + +Yet at the $i$-th day of the next $M$ days, one of the following events will occur. + + +1. A girl with property $A_i$ enters the store, intending to adopt a bunny. + + + - If there are bunnies available, she will adopt the $j$-th bunny with the minimum value of $|A_i-B_j|$. + + - If there are multiple bunnies with the same minimum $|A_i-B_j|$, she will choose the one whose $B_j$ is the smallest. + + - Otherwise, she will wait until one bunny chooses her. + +1. A bunny with property $B_i$ enters the store, willing to be adopted. + + + + - If there are girls waiting to adopt, it will choose the $j$-th girl with the minimum value of $|B_i-A_j|$ as its owner. + + - If there are multiple girls with the same minimum $|B_i-A_j|$, it will choose the one whose $A_j$ is the smallest. + + - Otherwise, it will stay at the store until one girl adopts it. + +Each time when girl $i$ adopted a bunny $j$ successfully, Satori will earn $|A_i-B_j|$ coins. + +Help Satori calculate the sum of coins she earns in total. + +### Input + +The first line contains a single integer $M(1\leq M\leq 3\times 10^5)$. + +The next $M$ lines each follows one of the two formats below: + +- `1 A_i` indicating a girl with property $A_i$ arrives $(1\leq A_i\leq 10^9)$. + +- `0 B_i` indicating a bunny with property $B_i$ arrives $(1\leq B_i\leq 10^9)$. + +It is guaranteed that all integers in $A$ and $B$ are distinct. + +### Output + +Output one single integer indicating the total money Satori earns. + +### Sample Input + +``` log +6 +1 5 +0 9 +0 3 +0 1 +1 2 +1 7 +``` + +### Sample Output + +``` log +9 +``` + +### HINT + +不要使用任何与堆和BST相关的STL! + +## 算法分析 (zh-CN) + +实现要点: +- 在线匹配问题:维护两个等待集合(girls 和 bunnies),到达新元素时尝试在对方集合中找到最接近的元素进行匹配,匹配规则为绝对差最小,若相同则选择属性值更小的那个。 +- 代码中使用 Treap(随机化平衡二叉搜索树)实现等待集合,支持插入、删除、前驱(floor)与后继(ceiling)查询,平均时间复杂度为 O(log N)。 +- 当新元素到达:在对方集合中查找 floor 与 ceiling,比较两者哪个与当前值差值更小并按规则选择,删除被匹配元素并累加收益;若没有匹配元素则将当前元素加入等待集合。 + +时间复杂度:每个事件平均 O(log Q),Q 为当前等待集合大小,总体 O(M log M) 其中 M 为事件数。 + +空间复杂度:O(M) 以存储等待元素与 Treap 节点。 + +正确性:按照题目规则每次总是选择当前可行的最优匹配(局部最优),题目保证属性值互不相同,避免平局歧义。 + +注意事项与边界: +- 属性值互不相同,有利于查找与删除操作的唯一性。 +- 使用 64 位类型统计总收益以避免溢出。 diff --git a/algorithm/2021F/lab_08/lab_08_F/main.cpp b/algorithm/2021F/lab_08/lab_08_F/main.cpp new file mode 100644 index 00000000..dfd69f33 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_F/main.cpp @@ -0,0 +1,164 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_08_F { +#endif +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +static constexpr const char end{'\n'}; + +using i32 = int32_t; +using i64 = int64_t; + +struct Event { + i32 type; + i64 value; +}; + +struct ProblemInput { + i32 m; + std::vector events; +}; + +using ProblemOutput = i64; + +ProblemInput read_input(); + +ProblemOutput solve(const ProblemInput &in); + +void write_output(const ProblemOutput &out); + +int main() { + const auto in = read_input(); + const auto out = solve(in); + write_output(out); + return 0; +} + +ProblemInput read_input() { + ProblemInput in; + std::cin >> in.m; + in.events.resize(static_cast(in.m)); + for (i32 i = 0; i < in.m; ++i) { + auto &ev = in.events[static_cast(i)]; + std::cin >> ev.type >> ev.value; + } + return in; +} + +// Replace Treap with std::multiset for ordered waiting sets +// multiset supports insert, erase(one element), lower_bound for ceiling +// and predecessor can be found by stepping iterator backward when needed. +using WaitingSet = std::multiset; + +struct MatchResult { + bool matched; + i64 partner_value; + i64 gain; +}; + +MatchResult try_match(WaitingSet &waiting, const i64 value) { + if (waiting.empty()) return MatchResult{false, 0, 0}; + + // ceiling: first element >= value + auto it = waiting.lower_bound(value); + bool has_ceil = it != waiting.end(); + bool has_floor = false; + i64 ceil_value = 0; + i64 floor_value = 0; + if (has_ceil) { + ceil_value = *it; + } + if (it != waiting.begin()) { + auto itf = it; + if (itf == waiting.end() || *itf >= value) --itf; + floor_value = *itf; + has_floor = true; + } + + if (!has_floor && !has_ceil) return MatchResult{false, 0, 0}; + + i64 chosen = 0; + if (has_floor && has_ceil) { + const i64 diff_floor = std::llabs(value - floor_value); + const i64 diff_ceil = std::llabs(value - ceil_value); + if (diff_floor < diff_ceil) { + chosen = floor_value; + } else if (diff_floor > diff_ceil) { + chosen = ceil_value; + } else { + chosen = std::min(floor_value, ceil_value); + } + } else if (has_floor) { + chosen = floor_value; + } else { + chosen = ceil_value; + } + + // erase one instance of chosen + auto eit = waiting.find(chosen); + if (eit != waiting.end()) waiting.erase(eit); + const i64 gain = std::llabs(value - chosen); + return MatchResult{true, chosen, gain}; +} + +ProblemOutput solve(const ProblemInput &in) { + WaitingSet waiting_girls; + WaitingSet waiting_bunnies; + i64 total_gain = 0; + + for (const auto &ev: in.events) { + if (ev.type == 1) { + const auto result = try_match(waiting_bunnies, ev.value); + if (result.matched) { + total_gain += result.gain; + } else { + waiting_girls.insert(ev.value); + } + } else { + const auto result = try_match(waiting_girls, ev.value); + if (result.matched) { + total_gain += result.gain; + } else { + waiting_bunnies.insert(ev.value); + } + } + } + + return total_gain; +} + +void write_output(const ProblemOutput &out) { + std::cout << out << end; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_08/lab_08_F/resource/01.data.in b/algorithm/2021F/lab_08/lab_08_F/resource/01.data.in new file mode 100644 index 00000000..d39e72b2 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_F/resource/01.data.in @@ -0,0 +1,7 @@ +6 +1 5 +0 9 +0 3 +0 1 +1 2 +1 7 diff --git a/algorithm/2021F/lab_08/lab_08_F/resource/01.data.out b/algorithm/2021F/lab_08/lab_08_F/resource/01.data.out new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_F/resource/01.data.out @@ -0,0 +1 @@ +9 diff --git a/algorithm/2021F/lab_08/lab_08_F/test.cpp b/algorithm/2021F/lab_08/lab_08_F/test.cpp new file mode 100644 index 00000000..b17bf491 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_F/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_08/lab_08_F/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_08_F { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 08_F]", "[test 08_F]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_08/lab_08_G/CMakeLists.txt b/algorithm/2021F/lab_08/lab_08_G/CMakeLists.txt new file mode 100644 index 00000000..768dc1e2 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER G) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_08/lab_08_G/README.md b/algorithm/2021F/lab_08/lab_08_G/README.md new file mode 100644 index 00000000..60a59ce3 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/README.md @@ -0,0 +1,43 @@ +# lab_08_G + +> TODO, 21组用例还是无法解决这个问题 + +## Description + +Given a weighted tree with $N$ nodes. + +The distance of a simple path is defined as the sum of all edges in the path. + +You should choose $M$ simple paths with no edge intersection between any two paths. + +Two paths can intersect at nodes, but not share edges. + +Now you are asked to calculate the maximum distance of the shortest path. + +### Input + +The first line contains two integers $N$ and $M$ $(1\leq M< N\leq 5\times 10^4)$. + +The next $N-1$ lines each contain three integers $x,y,w$, denoting there is an edge with weight $w$ connecting $x$ and $y$ $(1\leq x,y\leq N, 1\leq w\leq 10^4)$. + +### Output + +Output one single integer, indicating the maximum distance of the shortest path. + +### Sample Input + +``` log +7 1 +1 2 10 +1 3 5 +2 4 9 +2 5 8 +3 6 6 +3 7 7 +``` + +### Sample Output + +``` log +31 +``` diff --git a/algorithm/2021F/lab_08/lab_08_G/main.cpp b/algorithm/2021F/lab_08/lab_08_G/main.cpp new file mode 100644 index 00000000..04abf868 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/main.cpp @@ -0,0 +1,231 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include +#include + +namespace tree { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { + public: + // 边的结构体定义 + std::vector head; // head[i] 存储顶点i的第一条边的索引 + std::vector edges; // 存储所有边的数组 + int32_t edge_count; // 当前边的总数 + public: + /** + * @brief 构造函数 + * @param num_nodes 顶点的数量 (假设顶点编号从 1 到 num_nodes) + * @param max_edges 预估的最大边数 (对于无向图,一条无向边算两条有向边) + */ + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + // 初始化头节点数组,大小为顶点数+1,方便1-based 索引 + // 所有顶点的初始头节点都设为-1,表示没有出边 + head.assign(num_nodes + 1, -1); + // 预分配存储所有边的空间 + edges.resize(max_edges); + } + + /** + * @brief 添加一条有向边 + * @param u 起点 + * @param v 终点 + * @param w 权重 + */ + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + // 在边数组的末尾添加新边 + edges[edge_count].to = v; + edges[edge_count].weight = w; + // 新边的 next 指向原来以 u 为起点的第一条边 + edges[edge_count].next = head[u]; + // 更新以 u 为起点的第一条边为当前新添加的边 + head[u] = edge_count; + // 边计数器加一 + edge_count++; + } + + /** + * @brief 添加一条无向边 + * @param u, v 顶点 + * @param w 权重 + */ + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + add_edge(u, v, w); + add_edge(v, u, w); + } +}; +} + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_08_G { +#endif +using std::cin; +using std::cout; +using std::tuple; +using std::vector; +static constexpr const char end{'\n'}; + +using i32 = int32_t; +using i64 = int64_t; +struct ProblemInput { + i32 n; + i32 m; + std::shared_ptr graph; + i64 total_weight; +}; + +using ProblemOutput = i64; + +ProblemInput read_input(); +ProblemOutput solve(const ProblemInput &in); +void write_output(const ProblemOutput &out); +static bool can_form_paths(const ProblemInput &in, const i64 limit); + +int main() { + const auto in = read_input(); + const auto out = solve(in); + write_output(out); + return 0; +} + +ProblemInput read_input() { + ProblemInput in; + std::cin >> in.n >> in.m; + int32_t u; + int32_t v; + int64_t w; + in.graph = std::make_shared(in.n, static_cast((in.n - 1) * 2)); + in.total_weight = 0; + for (i32 i = 0; i < in.n - 1; ++i) { + std::cin >> u >> v >> w; + in.graph->add_undirected_edge(u, v, w); + in.total_weight += w; + } + return in; +} + + +ProblemOutput solve(const ProblemInput &in) { + i64 left = 0; + i64 right = in.total_weight; + i64 answer = 0; + while (left <= right) { + const auto mid = (left + right) >> 1; + if (can_form_paths(in, mid)) { + answer = mid; + left = mid + 1; + } else { + right = mid - 1; + } + } + return answer; +} + +void write_output(const ProblemOutput &out) { + std::cout << out << end; +} + +static bool can_form_paths(const ProblemInput &in, const i64 limit) { + if (limit <= 0) return true; + const auto &graph = *in.graph; + const auto n = in.n; + std::vector parent(static_cast(n + 1), 0); + std::vector order; + order.reserve(static_cast(n)); + std::vector stack; + stack.reserve(static_cast(n)); + stack.push_back(1); + parent[1] = 0; + while (!stack.empty()) { + const auto u = stack.back(); + stack.pop_back(); + order.push_back(u); + for (auto ei = graph.head[static_cast(u)]; ei != -1; ei = graph.edges[static_cast(ei)].next) { + const auto &edge = graph.edges[static_cast(ei)]; + if (edge.to == parent[static_cast(u)]) continue; + parent[static_cast(edge.to)] = u; + stack.push_back(edge.to); + } + } + std::vector dp(static_cast(n + 1), 0); + int32_t formed = 0; + std::vector lengths; + std::vector used; + + for (auto it = order.rbegin(); it != order.rend(); ++it) { + const auto u = *it; + lengths.clear(); + for (auto ei = graph.head[static_cast(u)]; ei != -1; ei = graph.edges[static_cast(ei)].next) { + const auto &edge = graph.edges[static_cast(ei)]; + if (parent[static_cast(u)] == edge.to) continue; + lengths.push_back(dp[static_cast(edge.to)] + edge.weight); + } + + std::sort(lengths.rbegin(), lengths.rend()); + + used.assign(lengths.size(), false); + int32_t l = 0; + int32_t r = static_cast(lengths.size()) - 1; + + while (l < r) { + if (used[l]) { + l++; + continue; + } + while (l < r && (used[r] || lengths[l] + lengths[r] < limit)) { + r--; + } + if (l < r) { + formed++; + used[l] = used[r] = true; + l++; + r--; + } + } + + i64 carry = 0; + for(size_t i = 0; i < lengths.size(); ++i) { + if (!used[i]) { + if (lengths[i] >= limit) { + formed++; + used[i] = true; + } else { + carry = std::max(carry, lengths[i]); + } + } + } + dp[static_cast(u)] = carry; + } + return formed >= in.m; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/01.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/01.data.in new file mode 100644 index 00000000..07d0c77a --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/01.data.in @@ -0,0 +1,7 @@ +7 1 +1 2 10 +1 3 5 +2 4 9 +2 5 8 +3 6 6 +3 7 7 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/01.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/01.data.out new file mode 100644 index 00000000..e85087af --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/01.data.out @@ -0,0 +1 @@ +31 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/02.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/02.data.in new file mode 100644 index 00000000..4ff263b3 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/02.data.in @@ -0,0 +1,4 @@ +4 1 +1 2 2 +2 3 3 +3 4 4 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/02.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/02.data.out new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/02.data.out @@ -0,0 +1 @@ +9 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/03.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/03.data.in new file mode 100644 index 00000000..88ce70c7 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/03.data.in @@ -0,0 +1,4 @@ +4 2 +1 2 7 +1 3 5 +1 4 6 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/03.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/03.data.out new file mode 100644 index 00000000..1e8b3149 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/03.data.out @@ -0,0 +1 @@ +6 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/04.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/04.data.in new file mode 100644 index 00000000..94c4d50d --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/04.data.in @@ -0,0 +1,5 @@ +5 2 +1 2 4 +2 3 6 +3 4 8 +3 5 3 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/04.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/04.data.out new file mode 100644 index 00000000..f599e28b --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/04.data.out @@ -0,0 +1 @@ +10 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/05.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/05.data.in new file mode 100644 index 00000000..4174696a --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/05.data.in @@ -0,0 +1,6 @@ +6 2 +1 2 5 +1 3 3 +1 4 4 +2 5 6 +5 6 7 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/05.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/05.data.out new file mode 100644 index 00000000..7f8f011e --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/05.data.out @@ -0,0 +1 @@ +7 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/06.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/06.data.in new file mode 100644 index 00000000..c3e184ae --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/06.data.in @@ -0,0 +1,4 @@ +4 3 +1 2 9 +1 3 8 +1 4 7 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/06.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/06.data.out new file mode 100644 index 00000000..7f8f011e --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/06.data.out @@ -0,0 +1 @@ +7 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/07.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/07.data.in new file mode 100644 index 00000000..8fedee5a --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/07.data.in @@ -0,0 +1,7 @@ +7 2 +1 2 3 +2 3 4 +3 4 5 +1 5 6 +5 6 7 +5 7 8 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/07.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/07.data.out new file mode 100644 index 00000000..48082f72 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/07.data.out @@ -0,0 +1 @@ +12 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/08.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/08.data.in new file mode 100644 index 00000000..6bb8fccd --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/08.data.in @@ -0,0 +1,2 @@ +2 1 +1 2 5 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/08.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/08.data.out new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/08.data.out @@ -0,0 +1 @@ +5 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/09.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/09.data.in new file mode 100644 index 00000000..8e1134c1 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/09.data.in @@ -0,0 +1,11 @@ +11 5 +1 2 1 +1 3 2 +1 4 3 +1 5 4 +1 6 5 +1 7 6 +1 8 7 +1 9 8 +1 10 9 +1 11 10 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/09.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/09.data.out new file mode 100644 index 00000000..b4de3947 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/09.data.out @@ -0,0 +1 @@ +11 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/10.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/10.data.in new file mode 100644 index 00000000..e5e46ae6 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/10.data.in @@ -0,0 +1,10 @@ +10 1 +1 2 1 +2 3 1 +3 4 1 +4 5 1 +5 6 1 +6 7 1 +7 8 1 +8 9 1 +9 10 1 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/10.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/10.data.out new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/10.data.out @@ -0,0 +1 @@ +9 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/11.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/11.data.in new file mode 100644 index 00000000..c904edcc --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/11.data.in @@ -0,0 +1,10 @@ +10 4 +1 2 1 +2 3 1 +3 4 1 +4 5 1 +5 6 1 +6 7 1 +7 8 1 +8 9 1 +9 10 1 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/11.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/11.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/11.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/12.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/12.data.in new file mode 100644 index 00000000..02bef062 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/12.data.in @@ -0,0 +1,15 @@ +15 7 +1 2 1 +1 3 1 +2 4 1 +2 5 1 +3 6 1 +3 7 1 +4 8 1 +4 9 1 +5 10 1 +5 11 1 +6 12 1 +6 13 1 +7 14 1 +7 15 1 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/12.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/12.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/12.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/13.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/13.data.in new file mode 100644 index 00000000..65ff2670 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/13.data.in @@ -0,0 +1,13 @@ +13 4 +1 2 1 +2 3 1 +3 4 1 +1 5 10 +5 6 10 +6 7 10 +1 8 100 +8 9 100 +9 10 100 +1 11 1000 +11 12 1000 +12 13 1000 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/13.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/13.data.out new file mode 100644 index 00000000..64bb6b74 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/13.data.out @@ -0,0 +1 @@ +30 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/14.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/14.data.in new file mode 100644 index 00000000..b5b4277a --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/14.data.in @@ -0,0 +1,5 @@ +5 2 +1 2 10 +1 3 10 +1 4 10 +1 5 10 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/14.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/14.data.out new file mode 100644 index 00000000..b92677ed --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/14.data.out @@ -0,0 +1 @@ +20000 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/15.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/15.data.in new file mode 100644 index 00000000..ddc7b92a --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/15.data.in @@ -0,0 +1,8 @@ +8 2 +1 2 1 +2 3 2 +3 4 3 +4 5 4 +1 6 5 +6 7 6 +7 8 7 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/15.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/15.data.out new file mode 100644 index 00000000..f599e28b --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/15.data.out @@ -0,0 +1 @@ +10 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/16.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/16.data.in new file mode 100644 index 00000000..c90ea0b6 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/16.data.in @@ -0,0 +1,10 @@ +10 9 +1 2 1 +1 3 1 +1 4 1 +1 5 1 +1 6 1 +1 7 1 +1 8 1 +1 9 1 +1 10 1 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/16.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/16.data.out new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/16.data.out @@ -0,0 +1 @@ +1 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/17.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/17.data.in new file mode 100644 index 00000000..74c25ab3 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/17.data.in @@ -0,0 +1,8 @@ +8 3 +1 2 100 +1 3 1 +1 4 1 +2 5 1 +2 6 1 +3 7 1 +3 8 1 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/17.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/17.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/17.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/18.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/18.data.in new file mode 100644 index 00000000..f862fbdb --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/18.data.in @@ -0,0 +1,9 @@ +9 3 +1 2 2 +2 3 3 +3 4 5 +1 5 8 +5 6 13 +6 7 21 +1 8 34 +8 9 55 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/18.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/18.data.out new file mode 100644 index 00000000..b1bd38b6 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/18.data.out @@ -0,0 +1 @@ +13 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/19.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/19.data.in new file mode 100644 index 00000000..ce36bcb9 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/19.data.in @@ -0,0 +1,6 @@ +6 2 +1 2 1 +2 3 1 +3 4 100 +4 5 1 +5 6 1 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/19.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/19.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/19.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/20.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/20.data.in new file mode 100644 index 00000000..7e07d6f7 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/20.data.in @@ -0,0 +1,7 @@ +7 3 +1 2 1 +1 3 1 +1 4 1 +1 5 1 +1 6 1 +1 7 1 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/20.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/20.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/20.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/21.data.in b/algorithm/2021F/lab_08/lab_08_G/resource/21.data.in new file mode 100644 index 00000000..70dcde5b --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/21.data.in @@ -0,0 +1,16 @@ +16 1 +1 2 1 +2 3 1 +3 4 1 +4 5 1 +5 6 1 +6 7 1 +7 8 1 +8 9 1 +1 10 10 +10 11 10 +11 12 10 +12 13 10 +13 14 10 +14 15 10 +15 16 10 diff --git a/algorithm/2021F/lab_08/lab_08_G/resource/21.data.out b/algorithm/2021F/lab_08/lab_08_G/resource/21.data.out new file mode 100644 index 00000000..8e14edce --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/resource/21.data.out @@ -0,0 +1 @@ +78 diff --git a/algorithm/2021F/lab_08/lab_08_G/test.cpp b/algorithm/2021F/lab_08/lab_08_G/test.cpp new file mode 100644 index 00000000..d2e1f5a1 --- /dev/null +++ b/algorithm/2021F/lab_08/lab_08_G/test.cpp @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_08/lab_08_G/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_08_G { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; +TEST_CASE("just a test case [test 08_G]", "[test 08_G]") { + CHECK(true); +} +TEST_CASE("test case with sequence [test 08_G]", "[test 08_G][.]") { + CS203_sequence sequence{1, 21, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_09/CMakeLists.txt b/algorithm/2021F/lab_09/CMakeLists.txt new file mode 100644 index 00000000..900d0630 --- /dev/null +++ b/algorithm/2021F/lab_09/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROJECT_ORDER lab_09) +project(${PROJECT_NAME}_${PROJECT_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +set(dependencies A B C D E F G) +foreach (elementName IN LISTS dependencies) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${elementName}) +endforeach () +unset(dependencies) diff --git a/algorithm/2021F/lab_09/README.md b/algorithm/2021F/lab_09/README.md new file mode 100644 index 00000000..285e3d53 --- /dev/null +++ b/algorithm/2021F/lab_09/README.md @@ -0,0 +1,31 @@ +# Contest1107 - CS203 2021 Fall Lab 09 Graph + +> cid: 1108 + +Welcome to CS203 2021 Fall Lab 09! Enjoy this Lab! + +There are six problems for you to solve. + +Score: + +- A: 10 +- B: 15/10 +- C: 15/10 +- D: 20/15 +- E: 20/15 +- F: 20 +- G: undefined/20 + +Reading the samples and hints carefully can help you understand the problem. + +## Problem mapping + +| Problem | problem id | +|--------:|-----------:| +| A | 1286 | +| B | 1467 | +| C | 1388 | +| D | 1468 | +| E | 1245 | +| F | 1291 | +| G | 1469 | diff --git a/algorithm/2021F/lab_09/cs203.submit.csv b/algorithm/2021F/lab_09/cs203.submit.csv new file mode 100644 index 00000000..88f22a3e --- /dev/null +++ b/algorithm/2021F/lab_09/cs203.submit.csv @@ -0,0 +1,8 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 225, 5, 26, 51, 3, 48, 358, 17, 70, 271 +B, 231, 6, 145, 46, 4, 2, 79, 39, 552, 8, 102, 442 +C, 232, 614, 71, 27, 4, 126, 52, 1126, 9, 156, 961 +D, 185, 126, 87, 2, 2, 11, 39, 452, 9, 117, 326 +E, 219, 559, 125, 54, 240, 60, 1257, 13, 272, 972 +F, 172, 341, 108, 49, 2, 65, 38, 775, 4, 138, 633 +Total, 1264, 11, 1811, 488, 136, 10, 524, 276, 4520, 60, 855, 3605 diff --git a/algorithm/2021F/lab_09/cs217.submit.csv b/algorithm/2021F/lab_09/cs217.submit.csv new file mode 100644 index 00000000..55211164 --- /dev/null +++ b/algorithm/2021F/lab_09/cs217.submit.csv @@ -0,0 +1,9 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 28, 5, 6, 4, 43, 19, 24 +B, 29, 18, 1, 1, 15, 2, 66, 38, 28 +C, 30, 31, 2, 2, 65, 1, 34, 30 +D, 37, 24, 14, 1, 2, 7, 85, 2, 56, 27 +E, 30, 38, 2, 9, 7, 7, 93, 4, 43, 46 +F, 33, 36, 2, 10, 1, 4, 4, 90, 41, 49 +G, 45, 163, 45, 34, 20, 10, 317, 135, 182 +Total, 232, 315, 72, 53, 3, 48, 36, 759, 7, 366, 386 diff --git a/algorithm/2021F/lab_09/lab_09_A/CMakeLists.txt b/algorithm/2021F/lab_09/lab_09_A/CMakeLists.txt new file mode 100644 index 00000000..40897f09 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_A/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER A) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_09/lab_09_A/README.md b/algorithm/2021F/lab_09/lab_09_A/README.md new file mode 100644 index 00000000..ddbad7d4 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_A/README.md @@ -0,0 +1,65 @@ +# Problem A + +## Description + +Long time ago, there was a handsome prince named Pisces, who ruled a powerful kingdom. + +In his kingdom, there were $n$ cities along with $m$ directed roads connecting them. + +To better govern his kingdom, Pisces had decided to draw an adjacent matrix to represent the circulation relationship among these cities. + +In his matrix, if there are $a_{ij}$ roads from city $i$ to city $j$, we have $A[i][j] = a_{ij}$. + +Please help him solve this problem. + +### Input + +The first line contains an integer $T$ $(1\leq T\leq 10)$, which denotes the number of test cases. + +In each test case, the first line contains $2$ integers $n$ $(2\leq n\leq 1000)$ and $m$ $(1\leq m\leq 2000)$, indicating the number of cities and the number of roads. + +And in each of the next $m$ lines, there are $2$ integers $u$ and $v$ $(1\leq u,v\leq n)$, representing that there is a directed road from city $u$ to city $v$. + +### Output + +For each test case, print the adjacent matrix. + +### Sample Input + +``` log +2 +4 6 +1 2 +2 3 +3 4 +2 3 +4 2 +1 4 +3 4 +1 2 +3 2 +1 3 +3 1 +``` + +### Sample Output + +``` log +0 1 0 1 +0 0 2 0 +0 0 0 1 +0 1 0 0 +0 1 1 +0 0 0 +1 1 0 +``` + +### 题目分析 + +问题:给定有向图,将链式前向星表示转换为邻接矩阵输出。 + +思路:遍历 graph::Graph 的 head/edges 链表,将每条出边累加到矩阵对应单元。注意 graph 中为 1-based 编号,在构造矩阵时将索引减一。 + +复杂度:O(n + m) 构造,加上 O(n^2) 输出矩阵。 + +要点:遍历链式前向星时每条边访问一次,避免重复存储边列表。 diff --git a/algorithm/2021F/lab_09/lab_09_A/main.cpp b/algorithm/2021F/lab_09/lab_09_A/main.cpp new file mode 100644 index 00000000..f3133aac --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_A/main.cpp @@ -0,0 +1,168 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +// lab_09_A: adjacency matrix output + +#include +#include +#include +#include +#include +namespace graph { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { + public: + // 边的结构体定义 + std::vector head; // head[i] 存储顶点i的第一条边的索引 + std::vector edges; // 存储所有边的数组 + int32_t edge_count; // 当前边的总数 + public: + /** + * @brief 构造函数 + * @param num_nodes 顶点的数量 (假设顶点编号从 1 到 num_nodes) + * @param max_edges 预估的最大边数 (对于无向图,一条无向边算两条有向边) + */ + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + // 初始化头节点数组,大小为顶点数+1,方便1-based 索引 + // 所有顶点的初始头节点都设为-1,表示没有出边 + head.assign(num_nodes + 1, -1); + // 预分配存储所有边的空间 + edges.resize(max_edges); + } + + /** + * @brief 添加一条有向边 + * @param u 起点 + * @param v 终点 + * @param w 权重 + */ + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + // 在边数组的末尾添加新边 + edges[edge_count].to = v; + edges[edge_count].weight = w; + // 新边的 next 指向原来以 u 为起点的第一条边 + edges[edge_count].next = head[u]; + // 更新以 u 为起点的第一条边为当前新添加的边 + head[u] = edge_count; + // 边计数器加一 + edge_count++; + } + + /** + * @brief 添加一条无向边 + * @param u, v 顶点 + * @param w 权重 + */ + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + add_edge(u, v, w); + add_edge(v, u, w); + } +}; +} +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_09_A { +#endif +using std::int32_t; +using std::int64_t; +using std::size_t; +static constexpr const char end{'\n'}; + +using matrix = std::vector>; +using input_type = std::vector; +using output_type = std::vector; + +// Read all test cases and build graph objects +static input_type read_all() { + int32_t T = 0; + if (!(std::cin >> T)) return {}; + input_type cases; + cases.reserve(static_cast(T)); + + for (int32_t tc = 0; tc < T; ++tc) { + int32_t n = 0, m = 0; + std::cin >> n >> m; + // construct graph with n nodes and reserve m edges + graph::Graph g(n, m); + int32_t u = 0, v = 0; + for (int32_t i = 0; i < m; ++i) { + std::cin >> u >> v; + g.add_edge(u, v, 1); + } + cases.push_back(std::move(g)); + } + return cases; +} + +// Build adjacency matrix by traversing graph::Graph's internal edge list +static matrix build_matrix(const graph::Graph &g) { + // Graph stores head array of size n+1 (1-based nodes) + const size_t n = (g.head.size() > 0 ? g.head.size() - 1 : 0); + matrix A(n, std::vector(n, 0)); + for (size_t u = 1; u <= n; ++u) { + for (int32_t ei = g.head[u]; ei != -1; ei = g.edges[static_cast(ei)].next) { + const int32_t v = g.edges[static_cast(ei)].to; + if (v >= 1 && static_cast(v) <= n) { + A[u - 1][static_cast(v - 1)]++; + } + } + } + return A; +} + +// Compute outputs for all graphs +static output_type cal(const input_type &inputs) { + output_type outputs; + outputs.reserve(inputs.size()); + for (const auto &g : inputs) { + outputs.push_back(build_matrix(g)); + } + return outputs; +} + +// Print matrices to stdout +static void output_all(const output_type &outs) { + for (const auto &mat : outs) { + const size_t n = mat.size(); + for (size_t i = 0; i < n; ++i) { + for (size_t j = 0; j < n; ++j) { + if (j) { + std::cout << ' '; + } + std::cout << mat[i][j]; + } + std::cout << end; + } + } +} + +int main() { + const auto inputs = read_all(); + const auto results = cal(inputs); + output_all(results); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_09/lab_09_A/resource/01.data.in b/algorithm/2021F/lab_09/lab_09_A/resource/01.data.in new file mode 100644 index 00000000..af2b22f8 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_A/resource/01.data.in @@ -0,0 +1,13 @@ +2 +4 6 +1 2 +2 3 +3 4 +2 3 +4 2 +1 4 +3 4 +1 2 +3 2 +1 3 +3 1 diff --git a/algorithm/2021F/lab_09/lab_09_A/resource/01.data.out b/algorithm/2021F/lab_09/lab_09_A/resource/01.data.out new file mode 100644 index 00000000..b5fd66fb --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_A/resource/01.data.out @@ -0,0 +1,7 @@ +0 1 0 1 +0 0 2 0 +0 0 0 1 +0 1 0 0 +0 1 1 +0 0 0 +1 1 0 diff --git a/algorithm/2021F/lab_09/lab_09_A/test.cpp b/algorithm/2021F/lab_09/lab_09_A/test.cpp new file mode 100644 index 00000000..441be0a7 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_A/test.cpp @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_09/lab_09_A/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_09_A { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 09_A]", "[test 09_A]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_09/lab_09_B/CMakeLists.txt b/algorithm/2021F/lab_09/lab_09_B/CMakeLists.txt new file mode 100644 index 00000000..dac0839a --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_B/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER B) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_09/lab_09_B/README.md b/algorithm/2021F/lab_09/lab_09_B/README.md new file mode 100644 index 00000000..2b0a188c --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_B/README.md @@ -0,0 +1,51 @@ +# Problem B + +## Description + +We have a chess board. + +It has $8 \times 8$ grids, the index from bottom to top is 1-8, from left to right is a-h. + +The knight moves a 3×2 square at each step. + +Given the start position of the knight, please find the minimum number of steps he should perform to reach the end position. + +### Input + +The first line gives $t(1\leq t\leq 5000)$ indicating the total number of test data sets. + +Each subsequent row of $t$ will give a start point and an end point. + +### Output + +For each test case, print minimum number of steps needed to reach the end + +### Sample Input + +``` log +3 +f6 f6 +e2 e4 +e2 e3 +``` + +### Sample Output + +``` log +0 +2 +3 +``` + +### HINT + +### 题目分析 + +问题:骑士在 8x8 棋盘上的最短跳跃步数。 + +思路:预构造静态的骑士跳跃图(64 个顶点,最多 8 条出边),对每个查询用 BFS 求最短路。图使用链式前向星表示以满足复用要求。 + +复杂度:构造图 O(1)(常量),每次 BFS 最坏 O(V+E)=O(64)。 + +要点:坐标与编号之间转换要准确(chess_to_index),并对相同起点与终点返回 0。 + diff --git a/algorithm/2021F/lab_09/lab_09_B/main.cpp b/algorithm/2021F/lab_09/lab_09_B/main.cpp new file mode 100644 index 00000000..1e13226d --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_B/main.cpp @@ -0,0 +1,203 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { +public: + // 边的结构体定义 + std::vector head; // head[i] 存储顶点i的第一条边的索引 + std::vector edges; // 存储所有边的数组 + int32_t edge_count; // 当前边的总数 +public: + /** + * @brief 构造函数 + * @param num_nodes 顶点的数量 (假设顶点编号从 1 到 num_nodes) + * @param max_edges 预估的最大边数 (对于无向图,一条无向边算两条有向边) + */ + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + // 初始化头节点数组,大小为顶点数+1,方便1-based 索引 + // 所有顶点的初始头节点都设为-1,表示没有出边 + head.assign(num_nodes + 1, -1); + // 预分配存储所有边的空间 + edges.resize(max_edges); + } + + /** + * @brief 添加一条有向边 + * @param u 起点 + * @param v 终点 + * @param w 权重 + */ + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + // 在边数组的末尾添加新边 + edges[edge_count].to = v; + edges[edge_count].weight = w; + // 新边的 next 指向原来以 u 为起点的第一条边 + edges[edge_count].next = head[u]; + // 更新以 u 为起点的第一条边为当前新添加的边 + head[u] = edge_count; + // 边计数器加一 + edge_count++; + } + + /** + * @brief 添加一条无向边 + * @param u, v 顶点 + * @param w 权重 + */ + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + add_edge(u, v, w); + add_edge(v, u, w); + } +}; +} +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_09_B { +#endif +using std::int32_t; +using std::int64_t; +using std::size_t; +static constexpr const char end{'\n'}; + +// Input: for each test case we will store the knight graph and the start/end +struct TestCase { + int32_t s; + int32_t t; +}; + +using input_type = std::vector; +using output_type = std::vector; + +// Convert chess notation like "f6" to 1-based index (1..64) +static int32_t chess_to_index(const std::string &pos) { + if (pos.size() < 2) return -1; + const char file = pos[0]; + const char rank = pos[1]; + const int32_t x = file - 'a'; // 0..7 + const int32_t y = rank - '1'; // 0..7 + if (x < 0 || x >= 8 || y < 0 || y >= 8) return -1; + return y * 8 + x + 1; // 1-based +} + +// Build knight moves graph for 8x8 board using graph::Graph (1-based nodes) +static graph::Graph build_knight_graph() { + constexpr int32_t n = 64; + constexpr int32_t max_edges = 64 * 8; // upper bound + graph::Graph g(n, max_edges); + constexpr int dx[8] = {1, 2, 2, 1, -1, -2, -2, -1}; + constexpr int dy[8] = {2, 1, -1, -2, -2, -1, 1, 2}; + for (int r = 0; r < 8; ++r) { + for (int c = 0; c < 8; ++c) { + const int u = r * 8 + c + 1; + for (int k = 0; k < 8; ++k) { + const int nr = r + dy[k]; + const int nc = c + dx[k]; + if (nr >= 0 && nr < 8 && nc >= 0 && nc < 8) { + const int v = nr * 8 + nc + 1; + g.add_edge(u, v, 1); + } + } + } + } + return g; +} + +static const auto static_graph = build_knight_graph(); +// Read all test cases +static input_type read_all() { + int32_t T = 0; + if (!(std::cin >> T)) return {}; + input_type inputs; + inputs.reserve(static_cast(T)); + for (int32_t i = 0; i < T; ++i) { + std::string a, b; + std::cin >> a >> b; + const int32_t ai = chess_to_index(a); + const int32_t bi = chess_to_index(b); + // build a knight graph per test case (as requested) + inputs.push_back(TestCase{ai, bi}); + } + return inputs; +} + +// BFS on graph::Graph to compute minimum steps from s to t +static int32_t bfs_shortest(int32_t s, int32_t t) { + if (s == t) return 0; + const int32_t n = static_cast(static_graph.head.size()) - 1; + std::vector dist(static_cast(n + 1), -1); + std::queue q; + dist[static_cast(s)] = 0; + q.push(s); + while (!q.empty()) { + const int32_t u = q.front(); + q.pop(); + for (int32_t ei = static_graph.head[static_cast(u)]; + ei != -1; + ei = static_graph.edges[static_cast(ei)].next) { + const int32_t v = static_graph.edges[static_cast(ei)].to; + if (dist[static_cast(v)] == -1) { + dist[static_cast(v)] = dist[static_cast(u)] + 1; + if (v == t) return dist[static_cast(v)]; + q.push(v); + } + } + } + return -1; +} + +// Compute outputs for all input pairs +static output_type cal(const input_type &inputs) { + output_type outputs; + outputs.reserve(inputs.size()); + for (const auto >: inputs) { + outputs.push_back(bfs_shortest(gt.s, gt.t)); + } + return outputs; +} + +// Print results +static void output_all(const output_type &outs) { + for (const auto &v: outs) { + std::cout << v << end; + } +} + +int main() { + const auto inputs = read_all(); + const auto results = cal(inputs); + output_all(results); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_09/lab_09_B/resource/01.data.in b/algorithm/2021F/lab_09/lab_09_B/resource/01.data.in new file mode 100644 index 00000000..fa578407 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_B/resource/01.data.in @@ -0,0 +1,4 @@ +3 +f6 f6 +e2 e4 +e2 e3 diff --git a/algorithm/2021F/lab_09/lab_09_B/resource/01.data.out b/algorithm/2021F/lab_09/lab_09_B/resource/01.data.out new file mode 100644 index 00000000..1556c06e --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_B/resource/01.data.out @@ -0,0 +1,3 @@ +0 +2 +3 diff --git a/algorithm/2021F/lab_09/lab_09_B/test.cpp b/algorithm/2021F/lab_09/lab_09_B/test.cpp new file mode 100644 index 00000000..70f75bc1 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_B/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_09/lab_09_B/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_09_B { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 09_B]", "[test 09_B]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_09/lab_09_C/CMakeLists.txt b/algorithm/2021F/lab_09/lab_09_C/CMakeLists.txt new file mode 100644 index 00000000..f07d2e4c --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_C/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER C) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_09/lab_09_C/README.md b/algorithm/2021F/lab_09/lab_09_C/README.md new file mode 100644 index 00000000..4e3a89ed --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_C/README.md @@ -0,0 +1,51 @@ +# Problem C + +## Description + +Given a graph with $n$ nodes and $m$ edges, we define cycles as paths which start from and end at the same point. + +One day, a student thinks that graphs with cycles are very "bad" and graphs without cycles are really "good". + +But he does not know how to distinguish them. + +Can you help him? + +### Input + +Line 1: Two integers $n(1\le n\le 10^5)$ and $m(1\le m\le 10^5)$, which means the graph has $n$ nodes and $m$ edges. + +There are $m$ lines following: Line 2~(m+1): Two integers $u$, $v$ which means there is an undirected edge between node $u$ and node $v$. + +Node indices are integers in range $[1,n]$. + +### Output + +Print whether the given graph is bad or not. Use "Bad" to indicate that the graph is bad and "Good" otherwise. + +### Sample Input + +``` log +3 3 +1 2 +2 3 +1 3 +``` + +### Sample Output + +``` log +Bad +``` + +### HINT + +### 题目分析 + +问题:判断无向图是否含环(输出 "Bad"/"Good")。 + +思路:使用链式前向星构建无向图(实际在内部以有向边形式存储两次),利用并查集(DSU)遍历边集检测是否存在将两个已在同一集合的顶点连接的边,从而确定存在环。 + +复杂度:O(n + m α(n)),其中 α 为并查集反阿克曼函数。 + +要点:遍历链式前向星时每条无向边出现两次,采用 u < v 的策略只处理一次以免重复。 + diff --git a/algorithm/2021F/lab_09/lab_09_C/main.cpp b/algorithm/2021F/lab_09/lab_09_C/main.cpp new file mode 100644 index 00000000..ca8f9d4c --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_C/main.cpp @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { +public: + // 边的结构体定义 + std::vector head; // head[i] 存储顶点i的第一条边的索引 + std::vector edges; // 存储所有边的数组 + int32_t edge_count; // 当前边的总数 +public: + /** + * @brief 构造函数 + * @param num_nodes 顶点的数量 (假设顶点编号从 1 到 num_nodes) + * @param max_edges 预估的最大边数 (对于无向图,一条无向边算两条有向边) + */ + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + // 初始化头节点数组,大小为顶点数+1,方便1-based 索引 + // 所有顶点的初始头节点都设为-1,表示没有出边 + head.assign(num_nodes + 1, -1); + // 预分配存储所有边的空间 + edges.resize(max_edges); + } + + /** + * @brief 添加一条有向边 + * @param u 起点 + * @param v 终点 + * @param w 权重 + */ + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + // 在边数组的末尾添加新边 + edges[edge_count].to = v; + edges[edge_count].weight = w; + // 新边的 next 指向原来以 u 为起点的第一条边 + edges[edge_count].next = head[u]; + // 更新以 u 为起点的第一条边为当前新添加的边 + head[u] = edge_count; + // 边计数器加一 + edge_count++; + } + + /** + * @brief 添加一条无向边 + * @param u, v 顶点 + * @param w 权重 + */ + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + add_edge(u, v, w); + add_edge(v, u, w); + } +}; +} +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_09_C { +#endif +using std::cin; +using std::cout; +using std::vector; +static constexpr const char end{'\n'}; + +// We'll convert input into a Graph; store only the Graph (edges are in chain-forward-star) +struct GraphInput { + graph::Graph g; + + GraphInput(int32_t n, int32_t m): g(n, m * 2) { + } +}; + +using input_type = GraphInput; +using output_type = const char *; + +static constexpr const char *STR_BAD = "Bad"; +static constexpr const char *STR_GOOD = "Good"; + +// Read input and convert into graph::Graph + original edge list +static input_type read_input() { + int32_t n = 0, m = 0; + std::cin >> n >> m; + input_type input(n, m); + int32_t u = 0, v = 0; + for (int32_t i = 0; i < m; ++i) { + std::cin >> u >> v; + // add undirected edge to chain-forward-star Graph + input.g.add_undirected_edge(u, v, 1); + } + return input; +} + +// Disjoint set union (union-find) +struct DSU { + std::vector parent; + std::vector rank; + + explicit DSU(size_t n): parent(n + 1), rank(n + 1, 0) { + for (size_t i = 0; i <= n; ++i) parent[i] = static_cast(i); + } + + int32_t find(size_t x) { + if (parent[x] != x) { + parent[x] = find(parent[x]); + } + return parent[x]; + } + + bool unite(size_t a, size_t b) { + const int32_t pa = find(a); + const int32_t pb = find(b); + if (pa == pb) { + return false; + } + if (rank[pa] < rank[pb]) { + parent[pa] = pb; + } else if ( + rank[pa] > rank[pb]) { + parent[pb] = pa; + } else { + parent[pb] = pa; + rank[pa]++; + } + return true; + } +}; + +// Calculate whether graph has cycle: return "Bad" if cycle exists else "Good" +static output_type cal(const input_type &input) { + const int32_t n = static_cast(input.g.head.size()) - 1; + DSU dsu(static_cast(n)); + // traverse chain-forward-star; each undirected edge appears twice (u->v and v->u) + // process each undirected edge only once by requiring u < v + for (int32_t u = 1; u <= n; ++u) { + for (int32_t ei = input.g.head[static_cast(u)]; ei != -1; + ei = input.g.edges[static_cast(ei)].next) { + const int32_t v = input.g.edges[static_cast(ei)].to; + if (u < v) { + if (dsu.find(u) == dsu.find(v)) return STR_BAD; + dsu.unite(u, v); + } + } + } + return STR_GOOD; +} + +static void output_result(output_type res) { + std::cout << res << end; +} + +int main() { + const auto input_data = read_input(); + const auto output_data = cal(input_data); + output_result(output_data); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_09/lab_09_C/resource/01.data.in b/algorithm/2021F/lab_09/lab_09_C/resource/01.data.in new file mode 100644 index 00000000..350277fa --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_C/resource/01.data.in @@ -0,0 +1,4 @@ +3 3 +1 2 +2 3 +1 3 diff --git a/algorithm/2021F/lab_09/lab_09_C/resource/01.data.out b/algorithm/2021F/lab_09/lab_09_C/resource/01.data.out new file mode 100644 index 00000000..6258a58f --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_C/resource/01.data.out @@ -0,0 +1 @@ +Bad diff --git a/algorithm/2021F/lab_09/lab_09_C/test.cpp b/algorithm/2021F/lab_09/lab_09_C/test.cpp new file mode 100644 index 00000000..91432f76 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_C/test.cpp @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_09/lab_09_C/resource/";} + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_09_C { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 09_C]", "[test 09_C]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_09/lab_09_D/CMakeLists.txt b/algorithm/2021F/lab_09/lab_09_D/CMakeLists.txt new file mode 100644 index 00000000..564aeae5 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_D/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER D) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_09/lab_09_D/README.md b/algorithm/2021F/lab_09/lab_09_D/README.md new file mode 100644 index 00000000..f0713e7a --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_D/README.md @@ -0,0 +1,58 @@ +# Problem D + +## Description + +An $N\times M$ matrix of non-negative integers. + +Please take out several numbers from it such that the summation of these numbers is maximized. + +You should guarantee that any two taken out numbers are not adjacent. + +We say $a$ is adjacent to $b$ if $b$ is one of $a$'s 8-connected neighborhoods in the matrix. + +### Input + +The first row has a positive integer $T(1\leq T\leq 20)$, which indicates that there are T groups of data. For each set of data, the first row has two positive integers $N,M(1\leq N,M\leq 6)$, which describe the number matrix as N rows and M columns. The next N rows, with M non-negative integers in each row, describe this numerical matrix. + +### Output + +A total of T rows, one non-negative integer per row, and the output of the resulting answer. + +### Sample Input + +``` log +3 +4 4 +67 75 63 10 +29 29 92 14 +21 68 71 56 +8 67 91 25 +2 3 +87 70 85 +10 3 17 +3 3 +1 1 1 +1 99 1 +1 1 1 +``` + +### Sample Output + +``` log +271 +172 +99 +``` + +### HINT + +### 题目分析 + +问题:在 n×m 网格上选择若干格子使得任意两格子不在 8 邻域内,求最大权和。 + +思路:保留链式前向星构建 8 邻域图以满足要求,但实际算法采用逐行掩码 DP(mask DP)。对每一行枚举不相邻的掩码,状态转移检查当前行与前一行是否有垂直或对角冲突,转移更新最大和。 + +复杂度:`O(n * 2^m * 2^m)` (当 m 较小时可行)。 + +要点:预筛选行内合法掩码(无相邻位),转移时排除与前一行的竖直与对角冲突以保证 8 邻域约束。 + diff --git a/algorithm/2021F/lab_09/lab_09_D/main.cpp b/algorithm/2021F/lab_09/lab_09_D/main.cpp new file mode 100644 index 00000000..0a38d6c5 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_D/main.cpp @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +// lab_09_D: select non-adjacent numbers (8-connected) maximize sum + +#include +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; + int32_t next; + int64_t weight; +}; + +class Graph { +public: + std::vector head; + std::vector edges; + size_t edge_count; + +public: + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + head.assign(static_cast(num_nodes) + 1, -1); + edges.resize(static_cast(max_edges)); + } + + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + edges[edge_count].to = v; + edges[edge_count].weight = w; + edges[edge_count].next = head[static_cast(u)]; + head[static_cast(u)] = edge_count; + ++edge_count; + } + + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + add_edge(u, v, w); + add_edge(v, u, w); + } +}; +} +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_09_D { +#endif + +using std::int32_t; +using std::int64_t; +using size_type = std::size_t; +static constexpr char end = '\n'; + +struct TestCase { + int32_t n; + int32_t m; + std::vector > a; // values +}; + +using input_type = std::vector; +using output_type = std::vector; + +// Read all test cases +static input_type read_all() { + int32_t T = 0; + if (!(std::cin >> T)) return {}; + input_type cases; + cases.reserve(static_cast(T)); + for (int32_t tc = 0; tc < T; ++tc) { + TestCase c{}; + std::cin >> c.n >> c.m; + c.a.assign(static_cast(c.n), std::vector(static_cast(c.m), 0)); + for (int32_t i = 0; i < c.n; ++i) { + for (int32_t j = 0; j < c.m; ++j) { + std::cin >> c.a[static_cast(i)][static_cast(j)]; + } + } + cases.push_back(std::move(c)); + } + return cases; +} + +// For each test case compute answer using mask DP over rows +static output_type cal(const input_type &inputs) { + output_type outputs; + outputs.reserve(inputs.size()); + for (const auto &tc: inputs) { + const int32_t n = tc.n; + const int32_t m = tc.m; + + // Build graph representation (kept for compatibility) + const int32_t nodes = n * m; + graph::Graph g(nodes, nodes * 8); + constexpr int dr[8] = {-1, -1, -1, 0, 0, 1, 1, 1}; + constexpr int dc[8] = {-1, 0, 1, -1, 1, -1, 0, 1}; + for (int r = 0; r < n; ++r) { + for (int c = 0; c < m; ++c) { + const int u = r * m + c + 1; + for (int k = 0; k < 8; ++k) { + const int nr = r + dr[k]; + const int nc = c + dc[k]; + if (nr >= 0 && nr < n && nc >= 0 && nc < m) { + const int v = nr * m + nc + 1; + g.add_edge(u, v, 0); + } + } + } + } + + // Precompute valid masks and row sums + const int max_mask = 1 << m; + std::vector row_sum(max_mask, 0); + std::vector valid_mask(max_mask, 0); + for (int mask = 0; mask < max_mask; ++mask) { + if (mask & (mask << 1)) { + // adjacent in row + valid_mask[mask] = 0; + continue; + } + valid_mask[mask] = 1; + } + + // dp over rows: prev -> curr + constexpr int64_t NEG = std::numeric_limits::min() / 4; + std::vector dp_prev(max_mask, NEG), dp_curr(max_mask, NEG); + + // initialize for row 0 + for (int mask = 0; mask < max_mask; ++mask) { + if (!valid_mask[mask]) { + continue; + } + int64_t s = 0; + for (int col = 0; col < m; ++col) + if (mask & (1 << col)) { + { + s += tc.a[0][static_cast(col)]; + } + } + dp_prev[mask] = s; + } + + // process remaining rows + for (int row = 1; row < n; ++row) { + std::fill(dp_curr.begin(), dp_curr.end(), NEG); + for (int mask = 0; mask < max_mask; ++mask) { + if (!valid_mask[mask]) { + continue; + } + // compute row sum + int64_t s = 0; + for (int col = 0; col < m; ++col) { + if (mask & (1 << col)) { + s += tc.a[static_cast(row)][static_cast(col)]; + } + } + // transition from prev_mask + for (int pm = 0; pm < max_mask; ++pm) { + if (!valid_mask[pm]) { + continue; + } + // no vertical conflict and no diagonal conflict + if ((mask & pm) != 0) { + continue; + } + if (((mask << 1) & pm) != 0) { + continue; + } + if (((mask >> 1) & pm) != 0) { + continue; + } + dp_curr[mask] = std::max(dp_curr[mask], dp_prev[pm] + s); + } + } + dp_prev.swap(dp_curr); + } + + int64_t ans = 0; + for (int mask = 0; mask < max_mask; ++mask) { + if (valid_mask[mask]) { + ans = std::max(ans, dp_prev[mask]); + } + } + outputs.push_back(ans); + } + return outputs; +} + +// Output answers +static void output_all(const output_type &outs) { + for (const auto &v: outs) { + std::cout << v << end; + } +} + +int main() { + const auto inputs = read_all(); + const auto results = cal(inputs); + output_all(results); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_09/lab_09_D/resource/01.data.in b/algorithm/2021F/lab_09/lab_09_D/resource/01.data.in new file mode 100644 index 00000000..36e69e19 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_D/resource/01.data.in @@ -0,0 +1,13 @@ +3 +4 4 +67 75 63 10 +29 29 92 14 +21 68 71 56 +8 67 91 25 +2 3 +87 70 85 +10 3 17 +3 3 +1 1 1 +1 99 1 +1 1 1 diff --git a/algorithm/2021F/lab_09/lab_09_D/resource/01.data.out b/algorithm/2021F/lab_09/lab_09_D/resource/01.data.out new file mode 100644 index 00000000..be546fe1 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_D/resource/01.data.out @@ -0,0 +1,3 @@ +271 +172 +99 diff --git a/algorithm/2021F/lab_09/lab_09_D/test.cpp b/algorithm/2021F/lab_09/lab_09_D/test.cpp new file mode 100644 index 00000000..3963058e --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_D/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_09/lab_09_D/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_09_D { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 09_D]", "[test 09_D]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_09/lab_09_E/CMakeLists.txt b/algorithm/2021F/lab_09/lab_09_E/CMakeLists.txt new file mode 100644 index 00000000..f6252ecc --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_E/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER E) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_09/lab_09_E/README.md b/algorithm/2021F/lab_09/lab_09_E/README.md new file mode 100644 index 00000000..3c23c94a --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_E/README.md @@ -0,0 +1,55 @@ +# Problem E + +## Description + +Today is Valentine’s day, and Pisces is going to date with the beautiful princess in the neighboring kingdom. + +There are $n$ cities numbered from $1$ to $n$ on the mainland, with Pisces in city $1$ and the princess in city $n$. + +There are $m$ unidirectional roads among these $n$ cities. + +Usually, it takes Pisces $1$ unit of time to travel from one city to another, but due to the probable existence of thorns, rivers or even robbers, some of the roads will take $2$ units of time to travel. + +In other words, the cost of traveling from one city to another is either $1$ unit or $2$ units of time. + +Pisces wants to know the minimum time that he can meet the princess. + +### Input + +The first line contains $2$ integers $n$ $(2\le n\le 2*10^5)$ and $m$ $(1\le m\le4*10^5)$. + +In each of the next $m$ lines, there are $3$ integers $u$, $v$ $(1\le u,v\le n)$ and $w$ $(1\le w\le 2)$, which means there is a road from $u$ to $v$, and it takes $w$ unit(s) of time for Pisces to go through. + +### Output + +Print the minimum time in one line. Or, if he cannot reach the destination, print "-1" (without quotes). + +### Sample Input + +``` log +4 5 +1 2 1 +2 4 1 +2 3 2 +3 4 1 +1 3 1 +``` + +### Sample Output + +``` log +2 +``` + +### HINT + +### 题目分析 + +问题:有向图的单源最短路(权值为正),求 1 到 n 的最短距离。 + +思路:使用链式前向星存图,运行 Dijkstra(优先队列)。采用常见的距离数组和优先队列松弛操作,遇到目标节点可提前终止。 + +复杂度:O((n + m) log n)。 + +要点:用大常数表示 INF,优先队列可能插入多个同一顶点的距离条目,需要通过比较当前弹出项与 dist[] 过滤过期条目。 + diff --git a/algorithm/2021F/lab_09/lab_09_E/main.cpp b/algorithm/2021F/lab_09/lab_09_E/main.cpp new file mode 100644 index 00000000..11c3f990 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_E/main.cpp @@ -0,0 +1,150 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +// lab_09_E: shortest path with edge weights 1 or 2 + +#include +#include +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; + int32_t next; + int64_t weight; +}; + +class Graph { +public: + std::vector head; // 1-based + std::vector edges; + size_t edge_count; + +public: + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + head.assign(static_cast(num_nodes) + 1, -1); + edges.resize(static_cast(max_edges)); + } + + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + edges[edge_count].to = v; + edges[edge_count].weight = w; + edges[edge_count].next = head[static_cast(u)]; + head[static_cast(u)] = edge_count; + ++edge_count; + } +}; +} +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_09_E { +#endif +using std::cin; +using std::cout; +using std::int32_t; +using std::int64_t; +using std::tie; +using std::tuple; +using std::vector; +using size_type = std::size_t; +static constexpr const char end{'\n'}; + +// Input container +struct Input { + graph::Graph g; + int32_t n; + int32_t m; + + explicit Input(int32_t n_, int32_t m_) : g(n_, m_), n(n_), m(m_) { + } +}; + +using input_type = Input; +using output_type = int64_t; + +// Read single test case: n m, then m lines u v w +static input_type read_input() { + int32_t n = 0, m = 0; + if (!(std::cin >> n >> m)) { + return Input(0, 0); + } + input_type input(n, m); + int32_t u = 0, v = 0; + int64_t w = 0; + for (int32_t i = 0; i < m; ++i) { + std::cin >> u >> v >> w; + if (u >= 1 && u <= n && v >= 1 && v <= n) { + input.g.add_edge(u, v, w); + } + } + return input; +} + +// Dijkstra from 1 to n using chain-forward-star +static output_type cal(const input_type &input) { + const int32_t n = input.n; + if (n <= 0) return -1; + constexpr int64_t INF = std::numeric_limits::max() / 4; + std::vector dist(static_cast(n + 1), INF); + using Pair = std::pair; // dist, node + std::priority_queue, std::greater > pq; + + dist[1] = 0; + pq.emplace(0, 1); + + while (!pq.empty()) { + int64_t d; + int32_t u; + std::tie(d, u) = pq.top(); + pq.pop(); + if (d != dist[static_cast(u)]) continue; + if (u == n) break; // early exit + for (int32_t ei = input.g.head[static_cast(u)]; ei != -1; + ei = input.g.edges[static_cast(ei)].next) { + const int32_t v = input.g.edges[static_cast(ei)].to; + const int64_t w = input.g.edges[static_cast(ei)].weight; + if (dist[static_cast(v)] > d + w) { + dist[static_cast(v)] = d + w; + pq.emplace(dist[static_cast(v)], v); + } + } + } + + if (dist[static_cast(n)] >= INF / 2) { + return -1; + } + return dist[static_cast(n)]; +} + +static void output_result(const output_type &res) { + std::cout << res << end; +} + +int main() { + const auto input = read_input(); + const auto ans = cal(input); + output_result(ans); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_09/lab_09_E/resource/01.data.in b/algorithm/2021F/lab_09/lab_09_E/resource/01.data.in new file mode 100644 index 00000000..46f25123 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_E/resource/01.data.in @@ -0,0 +1,6 @@ +4 5 +1 2 1 +2 4 1 +2 3 2 +3 4 1 +1 3 1 diff --git a/algorithm/2021F/lab_09/lab_09_E/resource/01.data.out b/algorithm/2021F/lab_09/lab_09_E/resource/01.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_E/resource/01.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_09/lab_09_E/test.cpp b/algorithm/2021F/lab_09/lab_09_E/test.cpp new file mode 100644 index 00000000..68ab2384 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_E/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_09/lab_09_E/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_09_E { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 09_E]", "[test 09_E]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_09/lab_09_F/CMakeLists.txt b/algorithm/2021F/lab_09/lab_09_F/CMakeLists.txt new file mode 100644 index 00000000..3bd8bb2b --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_F/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER F) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_09/lab_09_F/README.md b/algorithm/2021F/lab_09/lab_09_F/README.md new file mode 100644 index 00000000..db34210a --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_F/README.md @@ -0,0 +1,68 @@ +# Problem F + +## Description + +To make the kingdom more prosperous, Pisces decides to ally with the elves living in the forest. + +However, the elven elders want to test Pisces, so they give him a simple question. + +Given a DAG with $n$ nodes and $m$ edges, the elven elders want to know the value of +$\sum^n_{i=1}\sum^n_{j=1}count(i,j)\cdot a_i\cdot b_j$ mod $(1e9 + 7)$, where $count(x,y)$ is defined by the number of different paths from $x$ to $y$ and $count(x,x) = 0$, and $a$, $b$ are $2$ given arrays. + +It is too hard for Pisces to answer this question, so he turns to you for help. + +### Input + +The first line contains an integer $T$ $(1\leq T \leq 10)$, which denotes the number of test cases. + +For each test case, the first line contains $2$ integers $n$ and $m$ $(1 \leq n, m \leq 10^5)$ + +— the number of nodes and the number of edges, respectively. Each of the next $n$ lines contains $2$ integers $a_i$ and $b_i$. + +And for the next $m$ lines, each line contains $2$ integers $u$ and $v$ denoting a directed edge going from node $u$ to node $v$ $(1\leq u,v \leq n)$. + +### Output + +For each test case, print the answer. + +### Sample Input + +``` log +3 +3 3 +1 1 +1 1 +1 1 +1 2 +1 3 +2 3 +2 2 +1 0 +0 2 +1 2 +1 2 +2 1 +500000000 0 +0 500000000 +1 2 +``` + +### Sample Output + +``` log +4 +4 +250000014 +``` + +### HINT + +### 题目分析 + +问题:给定 DAG,求 `S = sum_{i,j} count(i,j) * a_i * b_j` (count(i,j) 为不同路径数,count(i,i)=0),结果对 `1e9+7` 取模。 + +思路:使用链式前向星存图并记录入度,先做拓扑排序,然后从拓扑序倒序对每个节点计算 `g[u] = sum_{u->v} (b[v] + g[v])` (MOD 下计算)。最后答案为 `sum_i a[i] * g[i]`。这样每条路径贡献被线性地累计,避免枚举路径。 + +复杂度:O(n + m)。 + +要点:注意 MOD 运算与拓扑排序的正确性(若输入保证 DAG,则拓扑排序覆盖所有节点)。使用 1-based 存储时小心索引偏移。 diff --git a/algorithm/2021F/lab_09/lab_09_F/main.cpp b/algorithm/2021F/lab_09/lab_09_F/main.cpp new file mode 100644 index 00000000..589acbd9 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_F/main.cpp @@ -0,0 +1,200 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { + public: + // 边的结构体定义 + std::vector head; // head[i] 存储顶点i的第一条边的索引 + std::vector edges; // 存储所有边的数组 + int32_t edge_count; // 当前边的总数 + public: + /** + * @brief 构造函数 + * @param num_nodes 顶点的数量 (假设顶点编号从 1 到 num_nodes) + * @param max_edges 预估的最大边数 (对于无向图,一条无向边算两条有向边) + */ + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + // 初始化头节点数组,大小为顶点数+1,方便1-based 索引 + // 所有顶点的初始头节点都设为-1,表示没有出边 + head.assign(num_nodes + 1, -1); + // 预分配存储所有边的空间 + edges.resize(max_edges); + } + + /** + * @brief 添加一条有向边 + * @param u 起点 + * @param v 终点 + * @param w 权重 + */ + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + // 在边数组的末尾添加新边 + edges[edge_count].to = v; + edges[edge_count].weight = w; + // 新边的 next 指向原来以 u 为起点的第一条边 + edges[edge_count].next = head[u]; + // 更新以 u 为起点的第一条边为当前新添加的边 + head[u] = edge_count; + // 边计数器加一 + edge_count++; + } + + /** + * @brief 添加一条无向边 + * @param u, v 顶点 + * @param w 权重 + */ + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + add_edge(u, v, w); + add_edge(v, u, w); + } +}; +} +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_09_F { +#endif +using std::int32_t; +using std::int64_t; +using std::size_t; +using std::vector; +static constexpr const char end{'\n'}; + +static constexpr int64_t MOD = 1000000007LL; + +// Test case container: keep Graph, arrays a and b, and indegree for topo +struct TestCase { + graph::Graph g; + std::vector a; // 1-based + std::vector b; // 1-based + std::vector indeg; // 1-based + TestCase(int32_t n = 0, int32_t m = 0) : g(n, m), a(n + 1), b(n + 1), indeg(n + 1, 0) {} +}; + +using input_type = std::vector; +using output_type = std::vector; + +// Read all test cases +static input_type read_all() { + int32_t T = 0; + if (!(std::cin >> T)) return {}; + input_type cases; + cases.reserve(static_cast(T)); + for (int32_t tc = 0; tc < T; ++tc) { + int32_t n = 0, m = 0; + std::cin >> n >> m; + TestCase tcse(n, m); + for (int32_t i = 1; i <= n; ++i) { + int64_t ai = 0, bi = 0; + std::cin >> ai >> bi; + tcse.a[i] = ((ai % MOD) + MOD) % MOD; + tcse.b[i] = ((bi % MOD) + MOD) % MOD; + } + for (int32_t i = 0; i < m; ++i) { + int32_t u = 0, v = 0; + std::cin >> u >> v; + tcse.g.add_edge(u, v, 0); + // record indegree + if (v >= 1 && static_cast(v) < tcse.indeg.size()) tcse.indeg[v]++; + } + cases.push_back(std::move(tcse)); + } + return cases; +} + +// Solve one test case using topo DP: g_u = sum_{u->v}(b_v + g_v) +static int64_t solve_one(TestCase const &tc) { + const size_t n = tc.g.head.size() > 0 ? tc.g.head.size() - 1 : 0; + // copy indegree because we will mutate it + std::vector indeg = tc.indeg; + std::vector topo; + topo.reserve(n); + std::vector q; + q.reserve(n); + // push nodes with indeg==0 + for (size_t i = 1; i <= n; ++i) + if (indeg[i] == 0) q.push_back(static_cast(i)); + // simple queue via index + size_t qhead = 0; + while (qhead < q.size()) { + int32_t u = q[qhead++]; + topo.push_back(u); + for (int32_t ei = tc.g.head[u]; ei != -1; ei = tc.g.edges[static_cast(ei)].next) { + int32_t v = tc.g.edges[static_cast(ei)].to; + if (--indeg[static_cast(v)] == 0) q.push_back(v); + } + } + // If topo.size() != n, graph wasn't a DAG, but problem guarantees DAG. We'll proceed anyway. + std::vector gval(n + 1, 0); + // process in reverse topo + for (auto it = topo.rbegin(); it != topo.rend(); ++it) { + const int32_t u = *it; + int64_t sum = 0; + for (int32_t ei = tc.g.head[u]; ei != -1; ei = tc.g.edges[static_cast(ei)].next) { + const int32_t v = tc.g.edges[static_cast(ei)].to; + sum += tc.b[static_cast(v)]; + if (sum >= MOD) sum -= MOD; + sum += gval[static_cast(v)]; + if (sum >= MOD) sum -= MOD; + } + gval[static_cast(u)] = sum % MOD; + } + int64_t ans = 0; + for (size_t i = 1; i <= n; ++i) { + ans = (ans + (tc.a[i] * gval[i]) % MOD) % MOD; + } + return ans; +} + +static output_type cal(const input_type &cases) { + output_type outs; + outs.reserve(cases.size()); + for (const auto &tc : cases) { + outs.push_back(solve_one(tc)); + } + return outs; +} + +static void output_all(const output_type &outs) { + for (const auto &v : outs) { + std::cout << v << end; + } +} + +int main() { + const auto inputs = read_all(); + const auto results = cal(inputs); + output_all(results); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_09/lab_09_F/resource/01.data.in b/algorithm/2021F/lab_09/lab_09_F/resource/01.data.in new file mode 100644 index 00000000..5f9737d4 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_F/resource/01.data.in @@ -0,0 +1,17 @@ +3 +3 3 +1 1 +1 1 +1 1 +1 2 +1 3 +2 3 +2 2 +1 0 +0 2 +1 2 +1 2 +2 1 +500000000 0 +0 500000000 +1 2 diff --git a/algorithm/2021F/lab_09/lab_09_F/resource/01.data.out b/algorithm/2021F/lab_09/lab_09_F/resource/01.data.out new file mode 100644 index 00000000..a4dfe14c --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_F/resource/01.data.out @@ -0,0 +1,3 @@ +4 +4 +250000014 diff --git a/algorithm/2021F/lab_09/lab_09_F/test.cpp b/algorithm/2021F/lab_09/lab_09_F/test.cpp new file mode 100644 index 00000000..6649b753 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_F/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_09/lab_09_F/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_09_F { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 09_F]", "[test 09_F]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_09/lab_09_G/CMakeLists.txt b/algorithm/2021F/lab_09/lab_09_G/CMakeLists.txt new file mode 100644 index 00000000..768dc1e2 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_G/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER G) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_09/lab_09_G/README.md b/algorithm/2021F/lab_09/lab_09_G/README.md new file mode 100644 index 00000000..ee8c4f6d --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_G/README.md @@ -0,0 +1,79 @@ +# Problem G + +## Description + +Van is a boss of SF Express in Shenzhen. + +He has $n$ SF Express sites, these sites are connected by $m$ streets and the i-th site has $w_i$ staffs. + +To save the cost, Van wants to remove several staffs from them. + +However, there is a minimum number of staff requirement in each street, i.e., the j-th street should has at least $c_j$ staffs. + +The number of staffs in the j-th street is the sum of staffs in the two sites which are connected by j-th street. + +Now, please tell Van what is the minimum and maximum number of staffs you can remove such that the requirement of each street is exactly satisfied. + +"exactly" means the sum of the staffs in the two sides connected by j-th street is equal to the minimum number of staff requirement in it. + +If you cannot find a feasible solution, print "impossible". + +### Input + +The first line contains two integers the number of SF Express sites $n(1\leq n\leq 500000)$ and the number of streets $m(1\leq m\leq 3000000)$. + +The second line is divided by a space to give $n$ integers, the i-th integer $w(0\leq w\leq 10^6)$ representing the number of staves at the i-th site. + +The next $m$ rows each contain three integers $u,v(1\leq u,v\leq n)$, $c(0\leq c\leq 10^6)$, representing the number of staves needed to connect the u-th site and the v-th site in a street of c. + +### Output + +If a solution exists, output the minimum and maximum values separated by spaces. + +Otherwise print "impossible". + +### Sample Input + +``` log +3 2 +5 10 5 +1 2 5 +2 3 3 +``` + +### Sample Output + +``` log +12 15 +``` + +### HINT + +Due to the sheer volume of data, even C++ is recommended to use read-in optimisation, , something like: + +``` cpp +char BB[1<<15],*K=BB,*T=BB; +#define getc() (K==T&&(T=(K=BB)+fread(BB,1,1<<15,stdin),K==T)?0:*K()) +inline long long read() { + long long x=0;char ch=getc(); + while(ch<'0'||ch>'9') ch=getc(); + while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getc(); + return x; +} +``` + +Using scanf to read in may result in RE. + +### 题目分析 + +问题:给定无向图顶点初始权重 w_i 和每条边的要求 c_j(要求边两端权重之和等于 c_j),求能删除的员工数的最小与最大值,或判断不可能。 + +思路:将每个节点的最终值表示为 x_i。每条边 u-v 给出方程 x_u + x_v = c。把图分成连通块,对每个连通块把 x 表示成 x_i = alpha_i * t + beta_i(alpha_i ∈ {1,-1})。 + +通过 BFS 给出 alpha/beta;若遇到确定 t 的方程则固定 t。 + +对每个连通块在允许区间内选择使得整体 x 非负且不超过原有 w_i,从而得到该连通块在所有合法解下的 x_i 总和的最小值和最大值,最终转换为被删除人数的最小/最大值 = 总初始员工 - 总最终员工。 + +复杂度:O(n + m) (对每条边只访问常数次),需要注意数值边界与连通块内 t 的可行区间求交。 + +要点:在构造 alpha/beta 时要照顾无向边在链式前向星中出现两次的事实;连通分量中若出现矛盾或区间无解则无解。 diff --git a/algorithm/2021F/lab_09/lab_09_G/main.cpp b/algorithm/2021F/lab_09/lab_09_G/main.cpp new file mode 100644 index 00000000..c8e62c2b --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_G/main.cpp @@ -0,0 +1,291 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { +public: + // 边的结构体定义 + std::vector head; // head[i] 存储顶点i的第一条边的索引 + std::vector edges; // 存储所有边的数组 + int32_t edge_count; // 当前边的总数 +public: + /** + * @brief 构造函数 + * @param num_nodes 顶点的数量 (假设顶点编号从 1 到 num_nodes) + * @param max_edges 预估的最大边数 (对于无向图,一条无向边算两条有向边) + */ + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + // 初始化头节点数组,大小为顶点数+1,方便1-based 索引 + // 所有顶点的初始头节点都设为-1,表示没有出边 + head.assign(num_nodes + 1, -1); + // 预分配存储所有边的空间 + edges.resize(max_edges); + } + + /** + * @brief 添加一条有向边 + * @param u 起点 + * @param v 终点 + * @param w 权重 + */ + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + // 在边数组的末尾添加新边 + edges[edge_count].to = v; + edges[edge_count].weight = w; + // 新边的 next 指向原来以 u 为起点的第一条边 + edges[edge_count].next = head[u]; + // 更新以 u 为起点的第一条边为当前新添加的边 + head[u] = edge_count; + // 边计数器加一 + edge_count++; + } + + /** + * @brief 添加一条无向边 + * @param u, v 顶点 + * @param w 权重 + */ + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + add_edge(u, v, w); + add_edge(v, u, w); + } +}; +} +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_09_G { +#endif +using std::int32_t; +using std::int64_t; +using std::size_t; +static constexpr const char end{'\n'}; + +static constexpr int64_t MOD_INF = std::numeric_limits::max() / 4; + +struct TestCase { + graph::Graph g; + std::vector w; + + TestCase(int32_t n = 0, int32_t m = 0) : g(n, std::max(1, m * 2)), w(static_cast(n) + 1, 0) { + } +}; + +struct Answer { + bool possible{true}; + int64_t min_removed{0}; + int64_t max_removed{0}; +}; + +static TestCase read_all(); + +static Answer cal(const TestCase &tc); + +static void output_all(const Answer &ans); + +int main() { + const auto tc = read_all(); + const auto ans = cal(tc); + output_all(ans); + return 0; +} + +static TestCase read_all() { + int32_t n = 0, m = 0; + if (!(std::cin >> n >> m)) { + return {}; + } + TestCase tc(n, m); + for (int32_t i = 1; i <= n; ++i) { + int64_t wi = 0; + std::cin >> wi; + tc.w[static_cast(i)] = wi; + } + int32_t u = 0, v = 0; + int64_t c = 0; + for (int32_t i = 0; i < m; ++i) { + std::cin >> u >> v >> c; + tc.g.add_undirected_edge(u, v, c); + } + return tc; +} + +static Answer cal(const TestCase &tc) { + const size_t n = tc.w.size() > 0 ? tc.w.size() - 1 : 0; + Answer ans; + if (n == 0) { + ans.possible = true; + ans.min_removed = 0; + ans.max_removed = 0; + return ans; + } + + std::vector visited(n + 1, 0); + std::vector parity(n + 1, 0); + std::vector bias(n + 1, 0); + + int64_t total_w = 0; + for (size_t i = 1; i <= n; ++i) { + total_w += tc.w[i]; + } + + int64_t total_min_sum_x = 0; + int64_t total_max_sum_x = 0; + + std::vector queue; + queue.reserve(n); + std::vector component; + component.reserve(64); + + for (int32_t start = 1; static_cast(start) <= n; ++start) { + if (visited[static_cast(start)]) continue; + + queue.clear(); + component.clear(); + + visited[static_cast(start)] = 1; + parity[static_cast(start)] = 1; + bias[static_cast(start)] = 0; + queue.push_back(start); + component.push_back(start); + + bool has_fixed_t = false; + int64_t fixed_t = 0; + + size_t qhead = 0; + while (qhead < queue.size()) { + const int32_t u = queue[qhead++]; + for (int32_t ei = tc.g.head[static_cast(u)]; ei != -1; + ei = tc.g.edges[static_cast(ei)].next) { + const int32_t v = tc.g.edges[static_cast(ei)].to; + const int64_t c = tc.g.edges[static_cast(ei)].weight; + const int32_t new_parity = -parity[static_cast(u)]; + const int64_t new_bias = c - bias[static_cast(u)]; + if (!visited[static_cast(v)]) { + visited[static_cast(v)] = 1; + parity[static_cast(v)] = new_parity; + bias[static_cast(v)] = new_bias; + queue.push_back(v); + component.push_back(v); + } else { + if (parity[static_cast(v)] == new_parity) { + if (bias[static_cast(v)] != new_bias) { + ans.possible = false; + return ans; + } + } else { + const int64_t numerator = new_bias - bias[static_cast(v)]; + if ((numerator & 1LL) != 0) { + ans.possible = false; + return ans; + } + const int32_t denom = parity[static_cast(v)] - new_parity; // ±2 + const int64_t cand_t = numerator / denom; + if (!has_fixed_t) { + fixed_t = cand_t; + has_fixed_t = true; + } else if (fixed_t != cand_t) { + ans.possible = false; + return ans; + } + } + } + } + } + + int64_t low = -MOD_INF; + int64_t high = MOD_INF; + int64_t sum_alpha = 0; + int64_t sum_beta = 0; + + for (const int32_t node: component) { + const int32_t alpha = parity[static_cast(node)]; + const int64_t beta = bias[static_cast(node)]; + const int64_t w = tc.w[static_cast(node)]; + + if (alpha == 1) { + low = std::max(low, -beta); + high = std::min(high, w - beta); + } else { + low = std::max(low, beta - w); + high = std::min(high, beta); + } + if (low > high) { + ans.possible = false; + return ans; + } + sum_alpha += static_cast(alpha); + sum_beta += beta; + } + + if (has_fixed_t) { + if (fixed_t < low || fixed_t > high) { + ans.possible = false; + return ans; + } + const int64_t sum_x = sum_alpha * fixed_t + sum_beta; + total_min_sum_x += sum_x; + total_max_sum_x += sum_x; + } else { + const int64_t sum_when_low = sum_alpha * low + sum_beta; + const int64_t sum_when_high = sum_alpha * high + sum_beta; + int64_t comp_min_sum = 0; + int64_t comp_max_sum = 0; + if (sum_alpha > 0) { + comp_min_sum = sum_when_low; + comp_max_sum = sum_when_high; + } else if (sum_alpha < 0) { + comp_min_sum = sum_when_high; + comp_max_sum = sum_when_low; + } else { + comp_min_sum = sum_beta; + comp_max_sum = sum_beta; + } + total_min_sum_x += comp_min_sum; + total_max_sum_x += comp_max_sum; + } + } + + ans.min_removed = total_w - total_max_sum_x; + ans.max_removed = total_w - total_min_sum_x; + ans.possible = true; + return ans; +} + +static void output_all(const Answer &ans) { + if (!ans.possible) { + std::cout << "impossible" << end; + } else { + std::cout << ans.min_removed << ' ' << ans.max_removed << end; + } +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_09/lab_09_G/resource/01.data.in b/algorithm/2021F/lab_09/lab_09_G/resource/01.data.in new file mode 100644 index 00000000..fadb3620 --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_G/resource/01.data.in @@ -0,0 +1,4 @@ +3 2 +5 10 5 +1 2 5 +2 3 3 diff --git a/algorithm/2021F/lab_09/lab_09_G/resource/01.data.out b/algorithm/2021F/lab_09/lab_09_G/resource/01.data.out new file mode 100644 index 00000000..0b64712f --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_G/resource/01.data.out @@ -0,0 +1 @@ +12 15 diff --git a/algorithm/2021F/lab_09/lab_09_G/test.cpp b/algorithm/2021F/lab_09/lab_09_G/test.cpp new file mode 100644 index 00000000..0c57e85f --- /dev/null +++ b/algorithm/2021F/lab_09/lab_09_G/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_09/lab_09_G/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_09_G { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 09_G]", "[test 09_G]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_10/CMakeLists.txt b/algorithm/2021F/lab_10/CMakeLists.txt new file mode 100644 index 00000000..31a3b198 --- /dev/null +++ b/algorithm/2021F/lab_10/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROJECT_ORDER lab_10) +project(${PROJECT_NAME}_${PROJECT_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +set(dependencies A B C D E F G) +foreach (elementName IN LISTS dependencies) + add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${elementName}) +endforeach () +unset(dependencies) diff --git a/algorithm/2021F/lab_10/README.md b/algorithm/2021F/lab_10/README.md new file mode 100644 index 00000000..db8ecf22 --- /dev/null +++ b/algorithm/2021F/lab_10/README.md @@ -0,0 +1,31 @@ +# Contest1109 - CS203 2021 Fall Lab 10 Advanced Graph + +> cid: 1110 + +Welcome to CS203 2021 Fall Lab 10! Enjoy this Lab! + +There are six problems for you to solve. + +Score: + ++ A: 10 ++ B: 15/10 ++ C: 15/10 ++ D: 20/15 ++ E: 20/15 ++ F: 20/20 ++ G: undefined/20 + +Reading the samples and hints carefully can help you understand the problem. + +## Problems + +| Problem |problem id| +|---:|---:| +| A | 1470 | +| B | 1471 | +| C | 1473 | +| D | 1474 | +| E | 1294 | +| F | 1475 | +| G | 1476 | diff --git a/algorithm/2021F/lab_10/cs203.submit.csv b/algorithm/2021F/lab_10/cs203.submit.csv new file mode 100644 index 00000000..36f1cef3 --- /dev/null +++ b/algorithm/2021F/lab_10/cs203.submit.csv @@ -0,0 +1,8 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 235, 694, 100, 88, 9, 158, 75, 1359, 23, 256, 1080 +B, 201, 414, 162, 11, 5, 100, 39, 932, 6, 150, 776 +C, 190, 431, 246, 34, 10, 148, 53, 1112, 5, 180, 927 +D, 162, 208, 12, 2, 6, 86, 12, 488, 1, 147, 340 +E, 104, 388, 43, 17, 9, 94, 16, 671, 2, 119, 550 +F, 162, 434, 63, 7, 3, 76, 40, 785, 12, 186, 587 +Total, 1054, 2569, 626, 159, 42, 662, 235, 5347, 49, 1038, 4260 diff --git a/algorithm/2021F/lab_10/cs217.submit.csv b/algorithm/2021F/lab_10/cs217.submit.csv new file mode 100644 index 00000000..79e57399 --- /dev/null +++ b/algorithm/2021F/lab_10/cs217.submit.csv @@ -0,0 +1,9 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 34, 59, 5, 4, 1, 8, 22, 133, 1, 61, 71 +B, 34, 26, 16, 4, 6, 86, 34, 52 +C, 34, 23, 10, 12, 79, 29, 50 +D, 30, 34, 3, 1, 1, 17, 4, 90, 1, 55, 34 +E, 27, 25, 3, 3, 13, 1, 72, 27, 45 +F, 31, 76, 2, 3, 4, 116, 2, 48, 66 +G, 26, 54, 1, 9, 5, 95, 58, 37 +Total, 216, 297, 39, 8, 3, 66, 42, 671, 4, 312, 355 diff --git a/algorithm/2021F/lab_10/lab_10_A/CMakeLists.txt b/algorithm/2021F/lab_10/lab_10_A/CMakeLists.txt new file mode 100644 index 00000000..40897f09 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_A/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER A) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_10/lab_10_A/README.md b/algorithm/2021F/lab_10/lab_10_A/README.md new file mode 100644 index 00000000..74b3e5ba --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_A/README.md @@ -0,0 +1,47 @@ +## Description + +There are n cities and m roads, and each road has a length. + +These n cities are numbered from 1 to n. + +Please find the shortest path from city_1 to city_n. + +### Input + +The first line contains two integers n, m $ (1\leq n, m \leq 10^5) $, indicating that there are n cities, m roads. + +The next m lines, each line contains 3 integers, u, v, w $ (1\leq u, v \leq n, 1\leq w \leq 10^9) $, indicating that there is a unidirectional road from u to v, cost w. + +### Output + +Please output the minimum cost from city_1 to city_n in one line. + +If there is not exist a road from city_1 to city_n, please output -1. + +### Sample Input + +``` log +3 3 +1 2 2 +2 3 1 +1 3 1 +``` + +### Sample Output + +``` log +1 +``` + +### 算法分析 + +本题要求在有向图中计算从城市 1 到城市 n 的最短路径。 + +实现采用 Dijkstra 算法,适用于边权为非负的稀疏图。 + +- 首先用链式前向星存储所有边,空间和访问效率较高。 +- 用优先队列维护当前最短距离的节点,每次取出距离最小的节点进行松弛。 +- 对每条边,若能更新目标节点的距离,则入队。 +- 若最终无法到达城市 n,则输出 -1。 + +整体时间复杂度为 $O((n + m) \log n)$,空间复杂度为 $O(n + m)$,可高效处理 $n, m$ 均为 $10^5$ 级别的大图。 diff --git a/algorithm/2021F/lab_10/lab_10_A/main.cpp b/algorithm/2021F/lab_10/lab_10_A/main.cpp new file mode 100644 index 00000000..e1c1c73f --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_A/main.cpp @@ -0,0 +1,146 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +// lab_10_A: shortest path from 1 to n (Dijkstra) + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { +public: + std::vector head; // head[i] 存储顶点 i 的第一条边索引 + std::vector edges; // 存储所有边 + int32_t edge_count; // 当前边数量 + + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + head.assign(num_nodes + 1, -1); + edges.resize(max_edges); + } + + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + edges[edge_count].to = v; + edges[edge_count].weight = w; + edges[edge_count].next = head[u]; + head[u] = edge_count; + ++edge_count; + } +}; +} // namespace graph + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_10_A { +#endif +using std::int32_t; +using std::int64_t; +using std::size_t; + +static constexpr const char end{'\n'}; + +using input_type = std::vector; +using output_type = std::vector; + +// Read input and construct graph(s). +// The problem statement describes a single test case with n and m on the first line. +static input_type read_all() { + int32_t n = 0, m = 0; + if (!(std::cin >> n >> m)) return {}; + input_type cases; + cases.reserve(1); + graph::Graph g(n, m); + int32_t u = 0, v = 0; + int64_t w = 0; + for (int32_t i = 0; i < m; ++i) { + std::cin >> u >> v >> w; + g.add_edge(u, v, w); + } + cases.push_back(std::move(g)); + return cases; +} + +// Dijkstra for single graph, return -1 if unreachable +static int64_t dijkstra_shortest(const graph::Graph &g) { + const size_t n = (g.head.size() > 0 ? g.head.size() - 1 : 0); + if (n == 0) return -1; + const int src = 1; + const int dst = static_cast(n); + const int64_t INF = std::numeric_limits::max() / 4; + std::vector dist(n + 1, INF); + using P = std::pair; + std::priority_queue, std::greater

> pq; + dist[src] = 0; + pq.emplace(0, src); + while (!pq.empty()) { + int64_t d; + int32_t u; + std::tie(d, u) = pq.top(); + pq.pop(); + if (d != dist[u]) continue; + if (u == dst) break; + for (int32_t ei = g.head[u]; ei != -1; ei = g.edges[static_cast(ei)].next) { + const auto &e = g.edges[static_cast(ei)]; + const int32_t v = e.to; + const int64_t nd = d + e.weight; + if (nd < dist[v]) { + dist[v] = nd; + pq.emplace(nd, v); + } + } + } + if (dist[dst] >= INF / 2) return -1; + return dist[dst]; +} + +// Compute outputs for all input graphs +static output_type cal(const input_type &inputs) { + output_type outs; + outs.reserve(inputs.size()); + for (const auto &g: inputs) { + outs.push_back(dijkstra_shortest(g)); + } + return outs; +} + +// Print outputs one per line +static void output_all(const output_type &outs) { + for (const auto &v: outs) { + std::cout << v << end; + } +} + +int main() { + const auto inputs = read_all(); + const auto results = cal(inputs); + output_all(results); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_10/lab_10_A/resource/01.data.in b/algorithm/2021F/lab_10/lab_10_A/resource/01.data.in new file mode 100644 index 00000000..00e2f16d --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_A/resource/01.data.in @@ -0,0 +1,4 @@ +3 3 +1 2 2 +2 3 1 +1 3 1 diff --git a/algorithm/2021F/lab_10/lab_10_A/resource/01.data.out b/algorithm/2021F/lab_10/lab_10_A/resource/01.data.out new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_A/resource/01.data.out @@ -0,0 +1 @@ +1 diff --git a/algorithm/2021F/lab_10/lab_10_A/test.cpp b/algorithm/2021F/lab_10/lab_10_A/test.cpp new file mode 100644 index 00000000..ad7996e8 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_A/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_10/lab_10_A/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_10_A { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 10_A]", "[test 10_A]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_10/lab_10_B/CMakeLists.txt b/algorithm/2021F/lab_10/lab_10_B/CMakeLists.txt new file mode 100644 index 00000000..dac0839a --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_B/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER B) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_10/lab_10_B/README.md b/algorithm/2021F/lab_10/lab_10_B/README.md new file mode 100644 index 00000000..37c01941 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_B/README.md @@ -0,0 +1,51 @@ +## Description + +Given n cities and m roads. + +Sinzo wants to build these m roads one by one to guarantee all cities are connected, i.e., each city can reach all other cities. + +Sinzo wants to know how much roads after she built that all the n cities are connected. + +### Input + +The first line contains 2 integers, n, m $ (1\leq n, m \leq 10^5) $, indicating there are n cities and m roads to build. + +The next m lines, each line contains 2 integers u, v $ (1\leq u, v \leq n) $, indicating Sinzo wants to build a unidirectional road from u to v. + +Note that: these m roads are built in order. + +### Output + +Please output the minimum roads to build. + +If Sinzo build all m roads, the n cities are not connected, then output -1. + +### Sample Input + +``` log +4 5 +1 2 +2 3 +3 4 +1 3 +4 1 +``` + +### Sample Output + +``` log +5 +``` + +### 算法分析 + +本题要求在有向图中,按顺序依次加入边,找到第一个使所有城市强连通的时刻。 + +实现采用链式前向星存储边,分别维护正向和反向图。 + +- 每次二分查找前缀长度,判断前 k 条边是否使图强连通。 +- 强连通性判定通过两次 DFS(正向和反向),从 1 号城市出发,遍历所有可达节点。 +- 若两次遍历都能覆盖所有城市,则当前前缀满足要求。 +- 若所有边加入后仍不强连通,则输出 -1。 + +整体时间复杂度为 $O(m \log m \cdot n)$,适合 $n, m$ 均为 $10^5$ 级别的稀疏图。 diff --git a/algorithm/2021F/lab_10/lab_10_B/main.cpp b/algorithm/2021F/lab_10/lab_10_B/main.cpp new file mode 100644 index 00000000..65b0efdf --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_B/main.cpp @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; // 终点 + int32_t next; // 下一条边索引 + int64_t weight; // 权重 (未使用) +}; + +class Graph { +public: + std::vector head; // head[i] 为顶点 i 的第一条边索引 + std::vector edges; // 存储所有边 + int32_t edge_count; + + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + head.assign(num_nodes + 1, -1); + edges.resize(max_edges); + } + + void add_edge(const int32_t u, const int32_t v, const int64_t w = 0) { + edges[edge_count].to = v; + edges[edge_count].weight = w; + edges[edge_count].next = head[u]; + head[u] = edge_count; + ++edge_count; + } +}; +} + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_10_B { +#endif + +using std::cin; +using std::cout; +using std::vector; +static constexpr const char end{'\n'}; + +// Each case stores both forward and reverse graphs +struct Case { + graph::Graph forward; + graph::Graph reverse; + + Case(int32_t n, int32_t m): forward(n, m), reverse(n, m) { + } +}; + +using input_type = std::vector; +using output_type = std::vector; + +// Read input: single test case with n m then m directed edges (u v) +static input_type read_all() { + int32_t n = 0, m = 0; + if (!(cin >> n >> m)) return {}; + input_type cases; + cases.reserve(1); + Case cs(n, m); + int32_t u = 0, v = 0; + for (int32_t i = 0; i < m; ++i) { + cin >> u >> v; + cs.forward.add_edge(u, v, 0); + cs.reverse.add_edge(v, u, 0); + } + cases.push_back(std::move(cs)); + return cases; +} + +// Check whether first k edges make the directed graph strongly connected +static bool prefix_strongly_connected(const int32_t n, const graph::Graph &forward, const graph::Graph &reverse, + const int32_t k) { + if (n <= 1) { + return true; + } + std::vector vis(n + 1, 0); + std::vector stk; + stk.reserve(n); + stk.push_back(1); + vis[1] = 1; + int32_t cnt = 0; + while (!stk.empty()) { + const int32_t u = stk.back(); + stk.pop_back(); + ++cnt; + for (int32_t ei = forward.head[static_cast(u)]; ei != -1; + ei = forward.edges[static_cast(ei)].next) { + if (ei >= k) continue; + int32_t v = forward.edges[static_cast(ei)].to; + if (!vis[v]) { + vis[v] = 1; + stk.push_back(v); + } + } + } + if (cnt != n) return false; + // Reverse DFS + vis.assign(n + 1, 0); + cnt = 0; + stk.clear(); + stk.push_back(1); + vis[1] = 1; + while (!stk.empty()) { + const int32_t u = stk.back(); + stk.pop_back(); + ++cnt; + for (int32_t ei = reverse.head[static_cast(u)]; ei != -1; + ei = reverse.edges[static_cast(ei)].next) { + if (ei >= k) continue; + int32_t v = reverse.edges[static_cast(ei)].to; + if (!vis[v]) { + vis[v] = 1; + stk.push_back(v); + } + } + } + return cnt == n; +} + +// For each case compute minimal prefix length to be strongly connected, or -1 +static output_type cal(const input_type &inputs) { + output_type outs; + outs.reserve(inputs.size()); + for (const auto &cs: inputs) { + const auto n = static_cast(cs.forward.head.size() > 0 ? cs.forward.head.size() - 1 : 0); + const auto m = static_cast(cs.forward.edge_count); + if (n <= 1) { + outs.push_back(0); + continue; + } + int32_t l = 1, r = m, ans = -1; + while (l <= r) { + const int32_t mid = l + ((r - l) >> 1); + if (prefix_strongly_connected(n, cs.forward, cs.reverse, mid)) { + ans = mid; + r = mid - 1; + } else { + l = mid + 1; + } + } + if (ans == -1) outs.push_back(-1); + else outs.push_back(ans); + } + return outs; +} + +// Output results +static void output_all(const output_type &outs) { + for (const auto &v: outs) { + cout << v << end; + } +} + +int main() { + const auto inputs = read_all(); + const auto results = cal(inputs); + output_all(results); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_10/lab_10_B/resource/01.data.in b/algorithm/2021F/lab_10/lab_10_B/resource/01.data.in new file mode 100644 index 00000000..9b48e185 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_B/resource/01.data.in @@ -0,0 +1,6 @@ +4 5 +1 2 +2 3 +3 4 +1 3 +4 1 diff --git a/algorithm/2021F/lab_10/lab_10_B/resource/01.data.out b/algorithm/2021F/lab_10/lab_10_B/resource/01.data.out new file mode 100644 index 00000000..7ed6ff82 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_B/resource/01.data.out @@ -0,0 +1 @@ +5 diff --git a/algorithm/2021F/lab_10/lab_10_B/test.cpp b/algorithm/2021F/lab_10/lab_10_B/test.cpp new file mode 100644 index 00000000..cbf88db1 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_B/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_10/lab_10_B/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_10_B { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 10_B]", "[test 10_B]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_10/lab_10_C/CMakeLists.txt b/algorithm/2021F/lab_10/lab_10_C/CMakeLists.txt new file mode 100644 index 00000000..f07d2e4c --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_C/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER C) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_10/lab_10_C/README.md b/algorithm/2021F/lab_10/lab_10_C/README.md new file mode 100644 index 00000000..f18e24ad --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_C/README.md @@ -0,0 +1,45 @@ +## Description + +There are n cities, m bidirectional roads connect to these n cities, each road has a cost. + +These m roads ensure that n cities connect to each other. + +Please find out the minimum cost to connect these n cities. + +### Input + +The first line contains two integers n, m $ (1\leq n \leq 10^5, 1\leq m \leq 5*10^5) $, indicating there are n cities and m roads. + +The next m lines, each line contains three integers u, v, w $ (1\leq u, v \leq n, 1\leq w\leq 10^9) $, indicating that there is a road between u and v, cost w. + +### Output + +Please output the minimum cost to connect these n cities. + +### Sample Input + +``` log +4 4 +1 2 1 +2 3 1 +3 4 2 +1 4 8 +``` + +### Sample Output + +``` log +4 +``` + +### 算法分析 + +本题要求在无向连通图中,选取若干边使所有城市连通且总花费最小,即求最小生成树(MST)。 + +实现采用 Kruskal 算法: + +- 首先将所有边按权重升序排序。 +- 用并查集维护连通性,依次选取不形成环的最小边,累计总花费。 +- 当选取的边数达到 $n-1$ 时停止。 + +整体时间复杂度为 $O(m \log m)$,空间复杂度为 $O(n + m)$,适合 $n$ 达 $10^5$,$m$ 达 $5 \times 10^5$ 的大规模图。 diff --git a/algorithm/2021F/lab_10/lab_10_C/main.cpp b/algorithm/2021F/lab_10/lab_10_C/main.cpp new file mode 100644 index 00000000..10ea5260 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_C/main.cpp @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds + +#include +#include +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t u, v; + int64_t w; +}; + +class Graph { +public: + std::vector edges; + int32_t n, m; + + Graph(int32_t num_nodes, int32_t max_edges) : n(num_nodes), m(0) { + edges.reserve(static_cast(max_edges)); + } + + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + edges.push_back({u, v, w}); + ++m; + } +}; +} + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_10_C { +#endif +using std::cin; +using std::cout; +using std::vector; +static constexpr const char end{'\n'}; + +struct Case { + graph::Graph g; + + Case(int32_t n, int32_t m): g(n, m) { + } +}; + +using input_type = std::vector; +using output_type = std::vector; + +// 读取输入 +static input_type read_all() { + int32_t n = 0, m = 0; + if (!(cin >> n >> m)) return {}; + input_type cases; + cases.reserve(1); + Case cs(n, m); + for (int32_t i = 0; i < m; ++i) { + int32_t u = 0, v = 0; + int64_t w = 0; + cin >> u >> v >> w; + cs.g.add_undirected_edge(u, v, w); + } + cases.push_back(std::move(cs)); + return cases; +} + +// Kruskal MST +static int64_t kruskal_mst(const graph::Graph &g) { + const int32_t n = g.n; + std::vector fa(n + 1); + for (int32_t i = 1; i <= n; ++i) fa[i] = i; + auto find = [&](int32_t x) { + while (fa[x] != x) x = fa[x] = fa[fa[x]]; + return x; + }; + int64_t total = 0; + int32_t cnt = 0; + std::vector edges = g.edges; + std::sort(edges.begin(), edges.end(), [](const graph::Edge &a, const graph::Edge &b) { + return a.w < b.w; + }); + for (const auto &e: edges) { + int32_t fu = find(e.u), fv = find(e.v); + if (fu != fv) { + fa[fu] = fv; + total += e.w; + ++cnt; + if (cnt == n - 1) break; + } + } + return total; +} + +// 计算所有用例的结果 +static output_type cal(const input_type &inputs) { + output_type outs; + outs.reserve(inputs.size()); + for (const auto &cs: inputs) { + outs.push_back(kruskal_mst(cs.g)); + } + return outs; +} + +// 输出结果 +static void output_all(const output_type &outs) { + for (const auto &v: outs) { + cout << v << end; + } +} + +int main() { + const auto inputs = read_all(); + const auto results = cal(inputs); + output_all(results); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_10/lab_10_C/resource/01.data.in b/algorithm/2021F/lab_10/lab_10_C/resource/01.data.in new file mode 100644 index 00000000..ff806bf6 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_C/resource/01.data.in @@ -0,0 +1,5 @@ +4 4 +1 2 1 +2 3 1 +3 4 2 +1 4 8 diff --git a/algorithm/2021F/lab_10/lab_10_C/resource/01.data.out b/algorithm/2021F/lab_10/lab_10_C/resource/01.data.out new file mode 100644 index 00000000..b8626c4c --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_C/resource/01.data.out @@ -0,0 +1 @@ +4 diff --git a/algorithm/2021F/lab_10/lab_10_C/test.cpp b/algorithm/2021F/lab_10/lab_10_C/test.cpp new file mode 100644 index 00000000..2be5c1b4 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_C/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_10/lab_10_C/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_10_C { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence [test 10_C]", "[test 10_C]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_10/lab_10_D/CMakeLists.txt b/algorithm/2021F/lab_10/lab_10_D/CMakeLists.txt new file mode 100644 index 00000000..564aeae5 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_D/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER D) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_10/lab_10_D/README.md b/algorithm/2021F/lab_10/lab_10_D/README.md new file mode 100644 index 00000000..a9eced72 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_D/README.md @@ -0,0 +1,48 @@ +## Description + +There a big hexagon, the side length is n, so there are $3n^2+3n+1$ points, and $9n^2+3n$ edges. + +Each point has a weight. + +We define the weight of each edge as the multiplying result of the weight of two endpoints in it. + +Please find out the minimum cost to connect these $3n^2+3n+1$ points. + +### Input + +The first line contains an integer n $ (1\leq n\leq 200) $, indicating the edge length of the hexagon. + +The next $2n+1$ lines, line i contains $2n+1-|i-n-1|$ integers w $ (1\leq w\leq 10^6) $, indicating the weight of each node. + +### Output + +Output the minimum cost in one line. + +### Sample Input + +``` log +1 +2 2 +2 1 2 +2 2 +``` + +### Sample Output + +``` log +12 +``` + +### 算法分析 + +本题要求在六边形网格上求最小生成树。 + +算法采用链式前向星存储图结构,节点编号按输入顺序分配。 + +边权为相邻两点权值之积,遍历所有节点,按六边形规则连边。 + +最小生成树采用 Prim 算法,利用优先队列维护当前可达最小边权。 + +每次选择未访问的最小边权节点,累计权值,直到所有节点被访问。 + +整体时间复杂度 $O(N\log N)$,空间复杂度 $O(N)$,适合大规模稠密图。 diff --git a/algorithm/2021F/lab_10/lab_10_D/main.cpp b/algorithm/2021F/lab_10/lab_10_D/main.cpp new file mode 100644 index 00000000..abc7f8c7 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_D/main.cpp @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +// lab_10_D: minimum spanning tree on hexagonal grid +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { +public: + std::vector head; // head[i] 存储顶点 i 的第一条边索引 + std::vector edges; // 存储所有边 + int32_t edge_count; // 当前边数量 + + Graph(const int32_t num_nodes, const int32_t max_edges) : edge_count(0) { + head.assign(num_nodes + 1, -1); + edges.resize(static_cast(max_edges)); + } + + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + edges[edge_count].to = v; + edges[edge_count].weight = w; + edges[edge_count].next = head[u]; + head[u] = edge_count; + ++edge_count; + } + + void add_undirected_edge(const int32_t u, const int32_t v, const int64_t w) { + add_edge(u, v, w); + add_edge(v, u, w); + } +}; +} // namespace graph + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_10_D { +#endif +using std::int32_t; +using std::int64_t; +using std::size_t; + +static constexpr const char end{'\n'}; + +using input_type = std::vector; +using output_type = std::vector; + +static graph::Graph build_graph_from_input(const int32_t n); + +static input_type read_all(); + +static int64_t minimum_spanning_tree(const graph::Graph &g); + +static output_type cal(const input_type &inputs); + +static void output_all(const output_type &outs); + +int main() { + const auto inputs = read_all(); + const auto outs = cal(inputs); + output_all(outs); + return 0; +} + +static graph::Graph build_graph_from_input(const int32_t n) { + const auto node_count = static_cast(3 * n * n + 3 * n + 1); + const int64_t raw_edge_count = 9LL * n * n + 3LL * n; + const auto max_edges = static_cast(raw_edge_count * 2 + 8); + graph::Graph g(node_count, max_edges); + const auto rows = static_cast(2 * n + 1); + std::vector q_min(rows, 0); + std::vector q_max(rows, 0); + std::vector row_len(rows, 0); + std::vector > index(rows); + std::vector weights(static_cast(node_count + 1), 0); + int32_t current = 0; + for (int32_t i = 0; i < rows; ++i) { + const int32_t r = i - n; + const int32_t min_q = std::max(-n, -n - r); + const int32_t max_q = std::min(n, n - r); + q_min[i] = min_q; + q_max[i] = max_q; + const int32_t len = max_q - min_q + 1; + row_len[i] = len; + index[i].resize(static_cast(len)); + for (int32_t j = 0; j < len; ++j) { + int64_t w = 0; + std::cin >> w; + ++current; + weights[static_cast(current)] = w; + index[i][j] = current; + } + } + + for (int32_t i = 0; i < rows; ++i) { + const int32_t r = i - n; + for (int32_t j = 0; j < row_len[i]; ++j) { + const int32_t u = index[i][j]; + const int32_t q = q_min[i] + j; + if (j + 1 < row_len[i]) { + const int32_t v = index[i][static_cast(j + 1)]; + const int64_t weight = weights[u] * weights[v]; + g.add_undirected_edge(u, v, weight); + } + const int32_t next_row = r + 1; + if (next_row <= n) { + const int32_t i2 = next_row + n; + const int32_t q_cur = q; + if (q_cur >= q_min[i2] && q_cur <= q_max[i2]) { + const int32_t v = index[i2][static_cast(q_cur - q_min[i2])]; + const int64_t weight = weights[u] * weights[v]; + g.add_undirected_edge(u, v, weight); + } + const int32_t q_left = q_cur - 1; + if (q_left >= q_min[i2] && q_left <= q_max[i2]) { + const int32_t v = index[i2][static_cast( + q_left - q_min[i2])]; + const int64_t weight = weights[u] * weights[v]; + g.add_undirected_edge(u, v, weight); + } + } + } + } + + g.edges.resize(static_cast(g.edge_count)); + return g; +} + +static input_type read_all() { + int32_t n = 0; + if (!(std::cin >> n)) return {}; + input_type cases; + cases.reserve(1); + cases.emplace_back(build_graph_from_input(n)); + return cases; +} + +static int64_t minimum_spanning_tree(const graph::Graph &g) { + const size_t n = g.head.size() > 0 ? g.head.size() - 1 : 0; + if (n == 0) return 0; + constexpr int64_t INF = std::numeric_limits::max(); + std::vector min_weight(n + 1, INF); + std::vector used(n + 1, false); + using Item = std::pair; + std::priority_queue, std::greater > pq; + min_weight[1] = 0; + pq.emplace(0, 1); + int32_t visited = 0; + int64_t result = 0; + while (!pq.empty() && visited < static_cast(n)) { + const Item current = pq.top(); + pq.pop(); + const int64_t weight = current.first; + const int32_t node = current.second; + if (used[static_cast(node)]) continue; + used[static_cast(node)] = true; + ++visited; + result += weight; + for (int32_t ei = g.head[static_cast(node)]; ei != -1; ei = g.edges[static_cast(ei)].next) { + const auto &edge = g.edges[static_cast(ei)]; + if (!used[static_cast(edge.to)] && edge.weight < min_weight[static_cast(edge.to)]) { + min_weight[static_cast(edge.to)] = edge.weight; + pq.emplace(edge.weight, edge.to); + } + } + } + return result; +} + +static output_type cal(const input_type &inputs) { + output_type outs; + outs.reserve(inputs.size()); + for (const auto &g: inputs) { + outs.push_back(minimum_spanning_tree(g)); + } + return outs; +} + +static void output_all(const output_type &outs) { + for (const auto &value: outs) { + std::cout << value << end; + } +} + +static const auto faster_streams = [] { + std::srand(std::time(nullptr)); + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_10/lab_10_D/resource/01.data.in b/algorithm/2021F/lab_10/lab_10_D/resource/01.data.in new file mode 100644 index 00000000..a50dc89b --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_D/resource/01.data.in @@ -0,0 +1,4 @@ +1 +2 2 +2 1 2 +2 2 diff --git a/algorithm/2021F/lab_10/lab_10_D/resource/01.data.out b/algorithm/2021F/lab_10/lab_10_D/resource/01.data.out new file mode 100644 index 00000000..48082f72 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_D/resource/01.data.out @@ -0,0 +1 @@ +12 diff --git a/algorithm/2021F/lab_10/lab_10_D/test.cpp b/algorithm/2021F/lab_10/lab_10_D/test.cpp new file mode 100644 index 00000000..5ae258dc --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_D/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_10/lab_10_D/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_10_D { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 10_D]", "[test 10_D]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_10/lab_10_E/CMakeLists.txt b/algorithm/2021F/lab_10/lab_10_E/CMakeLists.txt new file mode 100644 index 00000000..f6252ecc --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_E/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER E) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_10/lab_10_E/README.md b/algorithm/2021F/lab_10/lab_10_E/README.md new file mode 100644 index 00000000..89751b2b --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_E/README.md @@ -0,0 +1,67 @@ +## Description + +Yuki is a magical girl and she has the ability to activate portals. + +The country Yuki lives in has $n$ cities and $m$ roads at certain distances. + +The cities are numbered from $1$ to $n$ and all the roads are unidirectional, that is a road from $u$ to $v$ cannot be passed from $v$ to $u$. + +Also, there are $p$ portals in the country, each of them connects two cities unidirectional with no distance. + +Since Yuki doesn't grasp magic thoroughly, she can activate at most $k$ portals. + +Now Yuki is curious about what is the minimum distance between $S$ and $T$ if she activates at most $k$ portals. + +### Input + +The first line contains four integers: $n$, $m$, $p$ and $k$ $ (1\leq n,m,p\leq 50\ 000,0\leq k\leq10) $ --- the number of cities, roads, portals and the number of portals Yuki can activate at most. + +Each of the next $m$ lines contains three integers: $u$, $v$ and $w$ $ (1 \leq u,\ v\leq n,1\leq w\leq 1\ 000\ 000) $, meaning that there is a unidirectional road from city $u$ to city $v$ at distance $w$. + +Each of the next $p$ lines contains two integer: $u$ and $v$ $ (1 \leq u,\ v\leq n) $, meaning that there is an inactive portal from city $u$ to $v$. + +Please note that when it is active, Yuki can only be teleported from city $u$ to $v$ unidirectionally. + +The last line contains two integers: $S$ and $T$ $ (1\leq S,T\leq n) $ --- the origin and destination. + +### Output + +Print one line with the result --- the minimum distance between city $S$ and $T$. + +It is guaranteed that Yuki can move from city $S$ to $T$ by activating at most $k$ portals. + +### Sample Input + +``` log +5 6 3 1 +1 3 4 +1 2 2 +3 5 6 +2 4 3 +3 4 1 +4 5 2 +2 3 +1 4 +1 2 +1 5 +``` + +### Sample Output + +``` log +2 +``` + +### 算法分析 + +本题为分层图最短路问题,允许激活至多 $k$ 个传送门。 + +算法将每个城市复制 $k+1$ 层,每层表示已用传送门数量。 + +普通道路在同一层连边,传送门在相邻层间连边且权值为 0。 + +采用 Dijkstra 算法在分层图上求 $S$ 到 $T$ 的最短距离。 + +每次扩展节点时,判断是否可用传送门,更新对应层的距离。 + +整体时间复杂度 $O((k+1)N\log((k+1)N))$,空间复杂度 $O((k+1)N)$,适合稀疏图和小 $k$。 diff --git a/algorithm/2021F/lab_10/lab_10_E/main.cpp b/algorithm/2021F/lab_10/lab_10_E/main.cpp new file mode 100644 index 00000000..a9e3f61a --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_E/main.cpp @@ -0,0 +1,188 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; + int32_t next; + int64_t weight; +}; + +class Graph { +public: + std::vector head; + std::vector edges; + int32_t edge_count; + + Graph(const int32_t num_nodes, const int32_t max_edges) : edge_count(0) { + head.assign(num_nodes + 1, -1); + edges.resize(static_cast(max_edges + 5)); + } + + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + edges[edge_count].to = v; + edges[edge_count].weight = w; + edges[edge_count].next = head[u]; + head[u] = edge_count; + ++edge_count; + } +}; +} // namespace graph + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_10_E { +#endif + +using std::int32_t; +using std::int64_t; +using std::size_t; +using std::vector; +static constexpr const char end{'\n'}; + +struct Case { + graph::Graph roads; + graph::Graph portals; + int32_t original_n; + int32_t k; + int32_t S; + int32_t T; + + Case(const int32_t n_, const int32_t max_roads, const int32_t max_portals) + : roads(n_, max_roads), portals(n_, max_portals), original_n(n_), k(0), S(0), T(0) { + } +}; + +using input_type = vector; +using output_type = vector; + +// Read input and build base graphs for roads and portals +static input_type read_all() { + int32_t n = 0, m = 0, p = 0, k = 0; + if (!(std::cin >> n >> m >> p >> k)) return {}; + input_type cases; + cases.reserve(1); + Case cs(n, m, p); + cs.k = k; + int32_t u = 0; + int32_t v = 0; + int64_t w = 0; + for (int32_t i = 0; i < m; ++i) { + std::cin >> u >> v >> w; + cs.roads.add_edge(u, v, w); + } + for (int32_t i = 0; i < p; ++i) { + std::cin >> u >> v; + cs.portals.add_edge(u, v, 0); + } + std::cin >> cs.S >> cs.T; + cases.push_back(std::move(cs)); + return cases; +} + +// Compute shortest distance with at most k portals +static int64_t solve(const Case &cs) { + const int32_t n = cs.original_n; + const int32_t layers = cs.k + 1; + const int32_t total_nodes = layers * n; + constexpr int64_t INF = std::numeric_limits::max() / 4; + vector dist(static_cast(total_nodes + 1), INF); + using Item = std::pair; + std::priority_queue, std::greater > pq; + const auto encode = [n](const int32_t layer, const int32_t node) -> int32_t { + return layer * n + node; + }; + const int32_t start_idx = encode(0, cs.S); + dist[static_cast(start_idx)] = 0; + pq.emplace(0, start_idx); + while (!pq.empty()) { + const Item current = pq.top(); + pq.pop(); + const int64_t d = current.first; + const int32_t idx = current.second; + if (d != dist[static_cast(idx)]) continue; + const int32_t layer = (idx - 1) / n; + const int32_t node = idx - layer * n; + if (node == cs.T) return d; + for (int32_t ei = cs.roads.head[static_cast(node)]; ei != -1; + ei = cs.roads.edges[static_cast(ei)].next) { + const auto &edge = cs.roads.edges[static_cast(ei)]; + const int32_t next_idx = encode(layer, edge.to); + const int64_t nd = d + edge.weight; + if (nd < dist[static_cast(next_idx)]) { + dist[static_cast(next_idx)] = nd; + pq.emplace(nd, next_idx); + } + } + if (layer < cs.k) { + for (int32_t ei = cs.portals.head[static_cast(node)]; ei != -1; + ei = cs.portals.edges[static_cast(ei)].next) { + const auto &edge = cs.portals.edges[static_cast(ei)]; + const int32_t next_idx = encode(layer + 1, edge.to); + if (d < dist[static_cast(next_idx)]) { + dist[static_cast(next_idx)] = d; + pq.emplace(d, next_idx); + } + } + } + } + int64_t ans = INF; + for (int32_t layer = 0; layer <= cs.k; ++layer) { + const int32_t idx = encode(layer, cs.T); + ans = std::min(ans, dist[static_cast(idx)]); + } + return ans; +} + +// Process all cases +static output_type cal(const input_type &cases) { + output_type outs; + outs.reserve(cases.size()); + for (const auto &cs: cases) { + outs.push_back(solve(cs)); + } + return outs; +} + +// Output each result +static void output_all(const output_type &outs) { + for (const auto &v: outs) + std::cout << v << end; +} + +int main() { + const auto cases = read_all(); + const auto results = cal(cases); + output_all(results); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_10/lab_10_E/resource/01.data.in b/algorithm/2021F/lab_10/lab_10_E/resource/01.data.in new file mode 100644 index 00000000..ba31b4ff --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_E/resource/01.data.in @@ -0,0 +1,11 @@ +5 6 3 1 +1 3 4 +1 2 2 +3 5 6 +2 4 3 +3 4 1 +4 5 2 +2 3 +1 4 +1 2 +1 5 diff --git a/algorithm/2021F/lab_10/lab_10_E/resource/01.data.out b/algorithm/2021F/lab_10/lab_10_E/resource/01.data.out new file mode 100644 index 00000000..0cfbf088 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_E/resource/01.data.out @@ -0,0 +1 @@ +2 diff --git a/algorithm/2021F/lab_10/lab_10_E/test.cpp b/algorithm/2021F/lab_10/lab_10_E/test.cpp new file mode 100644 index 00000000..eccc1a4c --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_E/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_10/lab_10_E/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_10_E { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 10_E]", "[test 10_E]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_10/lab_10_F/CMakeLists.txt b/algorithm/2021F/lab_10/lab_10_F/CMakeLists.txt new file mode 100644 index 00000000..3bd8bb2b --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_F/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER F) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_10/lab_10_F/README.md b/algorithm/2021F/lab_10/lab_10_F/README.md new file mode 100644 index 00000000..4ab2a62c --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_F/README.md @@ -0,0 +1,45 @@ +## Description + +There are n cities and m roads, each road is unidirectional. + +Sinzo wants to build some roads, to make each city can reach other cities. + +Please tell how many roads should Sinzo construct at least? + +### Input + +The first line contains two integers, n, m $ (1\leq n, m\leq 10^5) $, indicating the number of cities and the number of roads. + +The next m lines, each line contains two integers u, v, indicating there is a unidirectional road from u to v. + +### Output + +Please output the number of roads to construct in one line. + +### Sample Input + +``` log +4 4 +1 2 +2 3 +3 1 +3 4 +``` + +### Sample Output + +``` log +1 +``` + +### 算法分析 + +本题要求最少添加多少边使有向图强连通。 + +算法采用 Tarjan 算法求强连通分量(SCC),并统计每个分量的入度和出度。 + +若分量入度为 0,需有边指向该分量;出度为 0,需有边从该分量指向其他分量。 + +答案为入度为 0 和出度为 0 的分量数的最大值。 + +整体时间复杂度 $O(N+M)$,空间复杂度 $O(N+M)$,适合大规模稀疏图。 diff --git a/algorithm/2021F/lab_10/lab_10_F/main.cpp b/algorithm/2021F/lab_10/lab_10_F/main.cpp new file mode 100644 index 00000000..f3281d10 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_F/main.cpp @@ -0,0 +1,220 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +// lab_10_F: minimum edges to strongly connect directed graph +#include +#include +#include +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; // 边的终点 + int32_t next; // 同一个起点的下一条边的索引 + int64_t weight; // 边的权重 +}; + +class Graph { +public: + std::vector head; + std::vector edges; + int32_t edge_count; + + Graph(const int32_t num_nodes, const int32_t max_edges) : edge_count(0) { + head.assign(num_nodes + 1, -1); + edges.resize(static_cast(max_edges + 5)); + } + + void add_edge(const int32_t u, const int32_t v, const int64_t w) { + edges[static_cast(edge_count)].to = v; + edges[static_cast(edge_count)].weight = w; + edges[static_cast(edge_count)].next = head[static_cast(u)]; + head[static_cast(u)] = edge_count; + ++edge_count; + } +}; +} // namespace graph + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_10_F { +#endif +using std::int32_t; +using std::int64_t; +using std::size_t; +using std::vector; + +static constexpr const char end{'\n'}; + +struct Case { + graph::Graph graph; + int32_t n; + + Case(const int32_t nodes, const int32_t edges) : graph(nodes, edges), n(nodes) { + } +}; + +using input_type = vector; +using output_type = vector; + +static input_type read_all(); + +static output_type cal(const input_type &cases); + +static void output_all(const output_type &outs); + +static int32_t tarjan_scc(const graph::Graph &g, vector &comp); + +static int32_t solve_case(const Case &cs); + +int main() { + const auto cases = read_all(); + const auto outs = cal(cases); + output_all(outs); + return 0; +} + +static input_type read_all() { + int32_t n = 0; + int32_t m = 0; + if (!(std::cin >> n >> m)) return {}; + Case cs(n, m); + int32_t u = 0; + int32_t v = 0; + for (int32_t i = 0; i < m; ++i) { + std::cin >> u >> v; + cs.graph.add_edge(u, v, 0); + } + input_type cases; + cases.reserve(1); + cases.push_back(std::move(cs)); + return cases; +} + +static int32_t tarjan_scc(const graph::Graph &g, vector &comp) { + const int32_t n = static_cast(g.head.size()) - 1; + vector dfn(static_cast(n + 1), 0); + vector low(static_cast(n + 1), 0); + vector in_stack(static_cast(n + 1), 0); + vector node_stack; + node_stack.reserve(static_cast(n)); + struct Frame { + int32_t node; + int32_t edge; + int32_t child; + }; + vector dfs_stack; + dfs_stack.reserve(static_cast(n)); + int32_t timer = 0; + int32_t comp_cnt = 0; + for (int32_t start = 1; start <= n; ++start) { + if (dfn[static_cast(start)] != 0) continue; + dfs_stack.push_back(Frame{start, g.head[static_cast(start)], -1}); + dfn[static_cast(start)] = low[static_cast(start)] = ++timer; + in_stack[static_cast(start)] = 1; + node_stack.push_back(start); + while (!dfs_stack.empty()) { + Frame &frame = dfs_stack.back(); + const int32_t u = frame.node; + if (frame.child != -1) { + const int32_t child = frame.child; + if (low[static_cast(child)] < low[static_cast(u)]) { + low[static_cast(u)] = low[static_cast(child)]; + } + frame.child = -1; + } + if (frame.edge == -1) { + dfs_stack.pop_back(); + if (low[static_cast(u)] == dfn[static_cast(u)]) { + ++comp_cnt; + while (true) { + const int32_t x = node_stack.back(); + node_stack.pop_back(); + in_stack[static_cast(x)] = 0; + comp[static_cast(x)] = comp_cnt; + if (x == u) break; + } + } + continue; + } + const int32_t ei = frame.edge; + frame.edge = g.edges[static_cast(ei)].next; + const int32_t v = g.edges[static_cast(ei)].to; + if (dfn[static_cast(v)] == 0) { + dfs_stack.push_back(Frame{v, g.head[static_cast(v)], -1}); + dfn[static_cast(v)] = low[static_cast(v)] = ++timer; + in_stack[static_cast(v)] = 1; + node_stack.push_back(v); + frame.child = v; + continue; + } + if (in_stack[static_cast(v)] && dfn[static_cast(v)] < low[static_cast(u)]) { + low[static_cast(u)] = dfn[static_cast(v)]; + } + } + } + return comp_cnt; +} + +static int32_t solve_case(const Case &cs) { + const int32_t n = cs.n; + vector component(static_cast(n + 1), 0); + const int32_t comp_cnt = tarjan_scc(cs.graph, component); + if (comp_cnt == 1) return 0; + vector indeg(static_cast(comp_cnt + 1), 0); + vector outdeg(static_cast(comp_cnt + 1), 0); + for (int32_t u = 1; u <= n; ++u) { + const int32_t cu = component[static_cast(u)]; + for (int32_t ei = cs.graph.head[static_cast(u)]; ei != -1; + ei = cs.graph.edges[static_cast(ei)].next) { + const int32_t v = cs.graph.edges[static_cast(ei)].to; + const int32_t cv = component[static_cast(v)]; + if (cu != cv) { + ++outdeg[static_cast(cu)]; + ++indeg[static_cast(cv)]; + } + } + } + int32_t zero_in = 0; + int32_t zero_out = 0; + for (int32_t id = 1; id <= comp_cnt; ++id) { + if (indeg[static_cast(id)] == 0) ++zero_in; + if (outdeg[static_cast(id)] == 0) ++zero_out; + } + return std::max(zero_in, zero_out); +} + +static output_type cal(const input_type &cases) { + output_type outs; + outs.reserve(cases.size()); + for (const auto &cs: cases) { + outs.push_back(solve_case(cs)); + } + return outs; +} + +static void output_all(const output_type &outs) { + for (const auto &value: outs) { + std::cout << value << end; + } +} + +static const auto faster_streams = [] { + std::srand(std::time(nullptr)); + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_10/lab_10_F/resource/01.data.in b/algorithm/2021F/lab_10/lab_10_F/resource/01.data.in new file mode 100644 index 00000000..8176b607 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_F/resource/01.data.in @@ -0,0 +1,5 @@ +4 4 +1 2 +2 3 +3 1 +3 4 diff --git a/algorithm/2021F/lab_10/lab_10_F/resource/01.data.out b/algorithm/2021F/lab_10/lab_10_F/resource/01.data.out new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_F/resource/01.data.out @@ -0,0 +1 @@ +1 diff --git a/algorithm/2021F/lab_10/lab_10_F/test.cpp b/algorithm/2021F/lab_10/lab_10_F/test.cpp new file mode 100644 index 00000000..1132bca6 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_F/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_10/lab_10_F/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_10_F { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 10_F]", "[test 10_F]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_10/lab_10_G/CMakeLists.txt b/algorithm/2021F/lab_10/lab_10_G/CMakeLists.txt new file mode 100644 index 00000000..768dc1e2 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_G/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER G) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_10/lab_10_G/README.md b/algorithm/2021F/lab_10/lab_10_G/README.md new file mode 100644 index 00000000..84b04ddd --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_G/README.md @@ -0,0 +1,58 @@ +## Description + +There are n spies (numbered 1~n), some spies know who is spy. + +There are j spies can be caught, each cost $w_i$. + +Once these spy are caught, they will tell out all the spies he know. + +If all the spies can be caught, please output the minimum cost, otherwise, please output the minimum No. of the spies which cannot be caught. + +### Input + +The first line contains an integer n $ (1\leq n \leq 100000) $, indicating there are n spies in total. + +The second line contains an integer j $ (1\leq j \leq n) $, indicating there are j spies can be caught directly. + +The next j lines, each line contains two integers b, w $ (1\leq b \leq n, 1\leq w \leq 1000) $, indicating catch spy_b directly need cost w. + +The next line contains an integer k $ (1\leq k \leq 100000) $. + +The next k lines, each line contains two integer u, v $ (1\leq u, v \leq n) $, indicating spy_u knows the information of spy_v. + +### Output + +If all the spies can be caught, please output YES in the first line and output the minimum cost in the second line. + +If not all the spies can be caught, please output NO in the first line and output the minimum No. in the second line. + +### Sample Input + +``` log +3 +2 +1 10 +2 100 +2 +1 3 +2 3 +``` + +### Sample Output + +``` log +YES +110 +``` + +### 算法分析 + +本题为有向图的最小代价全覆盖问题。 + +算法先用 Tarjan 算法求强连通分量(SCC),每个分量统计可直接抓捕的间谍最小代价。 + +对每个分量,若入度为 0 且无可抓捕间谍,则无法全覆盖,输出最小编号。 + +否则,将所有入度为 0 的分量的最小代价累加,得到全覆盖的最小总代价。 + +整体时间复杂度 $O(N+K)$,空间复杂度 $O(N+K)$,适合大规模稀疏图和分层判定。 diff --git a/algorithm/2021F/lab_10/lab_10_G/main.cpp b/algorithm/2021F/lab_10/lab_10_G/main.cpp new file mode 100644 index 00000000..c887453c --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_G/main.cpp @@ -0,0 +1,205 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include + +namespace graph { +struct Edge { + int32_t to; + int32_t next; + int64_t weight; +}; + +class Graph { +public: + std::vector head; // 1-based + std::vector edges; + int32_t edge_count; + + Graph(int32_t num_nodes, int32_t max_edges) : edge_count(0) { + head.assign(num_nodes + 1, -1); + edges.resize(static_cast(max_edges)); + } + + void add_edge(int32_t u, int32_t v, int64_t w = 0) { + edges[edge_count].to = v; + edges[edge_count].weight = w; + edges[edge_count].next = head[u]; + head[u] = edge_count; + ++edge_count; + } +}; +} // namespace graph + +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else +namespace lab_10_G { +#endif +using std::int32_t; +using std::int64_t; +using std::vector; +static constexpr const char end{'\n'}; + +struct Case { + graph::Graph g; + vector cost; + int32_t n; + + Case(int32_t n_, int32_t m_, int32_t j_): g(n_, m_), cost(n_ + 1, -1), n(n_) { + } +}; + +static constexpr int64_t INF_COST = (int64_t) 4e18; + +struct Answer { + bool ok; + int64_t val; +}; + +using input_type = vector; +using output_type = vector; + +// Read all input (single case expected) +static input_type read_all() { + int32_t n = 0; + if (!(std::cin >> n)) return {}; + int32_t j = 0; + std::cin >> j; + Case cs(n, 0, j); // temp zero edges, will resize later + // store costs + for (int32_t i = 0; i < j; ++i) { + int32_t b; + int64_t w; + std::cin >> b >> w; + cs.cost[b] = w; + } + int32_t k = 0; + std::cin >> k; + cs.g = graph::Graph(n, k); // re-init graph with edge capacity k + for (int32_t i = 0; i < k; ++i) { + int32_t u, v; + std::cin >> u >> v; + cs.g.add_edge(u, v, 0); + } + input_type cases; + cases.reserve(1); + cases.push_back(std::move(cs)); + return cases; +} + +// Tarjan SCC +struct TarjanData { + vector dfn, low, comp, stack; + vector in_st; + int32_t timer{0}, comp_cnt{0}; +}; + +static void tarjan_dfs(int32_t u, const graph::Graph &g, TarjanData &td) { + td.dfn[u] = td.low[u] = ++td.timer; + td.stack.push_back(u); + td.in_st[u] = 1; + for (int32_t ei = g.head[u]; ei != -1; ei = g.edges[ei].next) { + int32_t v = g.edges[ei].to; + if (!td.dfn[v]) { + tarjan_dfs(v, g, td); + if (td.low[v] < td.low[u]) td.low[u] = td.low[v]; + } else if (td.in_st[v] && td.dfn[v] < td.low[u]) { + td.low[u] = td.dfn[v]; + } + } + if (td.low[u] == td.dfn[u]) { + ++td.comp_cnt; + while (true) { + int32_t x = td.stack.back(); + td.stack.pop_back(); + td.in_st[x] = 0; + td.comp[x] = td.comp_cnt; + if (x == u) break; + } + } +} + +static Answer solve(const Case &cs) { + const int32_t n = cs.n; + TarjanData td; + td.dfn.assign(n + 1, 0); + td.low.assign(n + 1, 0); + td.comp.assign(n + 1, 0); + td.in_st.assign(n + 1, 0); + td.stack.reserve(n); + for (int32_t i = 1; i <= n; ++i) if (!td.dfn[i]) tarjan_dfs(i, cs.g, td); + const int32_t C = td.comp_cnt; + vector indeg(C + 1, 0); + vector min_cost(C + 1, INF_COST); + vector comp_min_id(C + 1, 0); + // gather per component data + for (int32_t u = 1; u <= n; ++u) { + int32_t cu = td.comp[u]; + if (comp_min_id[cu] == 0 || u < comp_min_id[cu]) comp_min_id[cu] = u; + if (cs.cost[u] >= 0 && cs.cost[u] < min_cost[cu]) min_cost[cu] = cs.cost[u]; + for (int32_t ei = cs.g.head[u]; ei != -1; ei = cs.g.edges[ei].next) { + int32_t v = cs.g.edges[ei].to; + int32_t cv = td.comp[v]; + if (cu != cv) ++indeg[cv]; + } + } + int64_t total = 0; + int32_t bad_min = 0; + for (int32_t c = 1; c <= C; ++c) { + if (indeg[c] == 0) { + if (min_cost[c] >= INF_COST) { + // need but not available + int32_t cand = comp_min_id[c]; + if (bad_min == 0 || cand < bad_min) bad_min = cand; + } else { + total += min_cost[c]; + } + } + } + if (bad_min != 0) return {false, bad_min}; + return {true, total}; +} + +static output_type cal(const input_type &inputs) { + output_type outs; + outs.reserve(inputs.size()); + for (const auto &cs: inputs) { outs.push_back(solve(cs)); } + return outs; +} + +static void output_all(const output_type &outs) { + for (const auto &ans: outs) { + if (ans.ok) { + std::cout << "YES" << end << ans.val << end; + } else { + std::cout << "NO" << end << ans.val << end; + } + } +} + +int main() { + const auto inputs = read_all(); + const auto results = cal(inputs); + output_all(results); + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + std::ios::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_10/lab_10_G/resource/01.data.in b/algorithm/2021F/lab_10/lab_10_G/resource/01.data.in new file mode 100644 index 00000000..b63efee1 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_G/resource/01.data.in @@ -0,0 +1,7 @@ +3 +2 +1 10 +2 100 +2 +1 3 +2 3 diff --git a/algorithm/2021F/lab_10/lab_10_G/resource/01.data.out b/algorithm/2021F/lab_10/lab_10_G/resource/01.data.out new file mode 100644 index 00000000..8179240f --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_G/resource/01.data.out @@ -0,0 +1,2 @@ +YES +110 diff --git a/algorithm/2021F/lab_10/lab_10_G/test.cpp b/algorithm/2021F/lab_10/lab_10_G/test.cpp new file mode 100644 index 00000000..c204ac99 --- /dev/null +++ b/algorithm/2021F/lab_10/lab_10_G/test.cpp @@ -0,0 +1,48 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_10/lab_10_G/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_10_G { +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence [test 10_G]", "[test 10_G]") { + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_welcome/CMakeLists.txt b/algorithm/2021F/lab_welcome/CMakeLists.txt index b5eb98fa..687e0208 100644 --- a/algorithm/2021F/lab_welcome/CMakeLists.txt +++ b/algorithm/2021F/lab_welcome/CMakeLists.txt @@ -6,7 +6,7 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -set(dependencies A B C D E F) +set(dependencies A B C D E F G) foreach (elementName IN LISTS dependencies) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${elementName}) endforeach () diff --git a/algorithm/2021F/lab_welcome/README.md b/algorithm/2021F/lab_welcome/README.md new file mode 100644 index 00000000..0e4e320b --- /dev/null +++ b/algorithm/2021F/lab_welcome/README.md @@ -0,0 +1,37 @@ +# CS203/217 2021 Fall Welcome Lab + +``` meta +cid=1092 +``` + +Welcome to 2021 Fall Data Structures and Algorithm Analysis! + +There are 6/7 problems in this lab. + +Score: + ++ A: 10 ++ B: 15/10 ++ C: 15/10 ++ D: 20/15 ++ E: 20/15 ++ F: 20 ++ G: undefined/20 + +> CS217 Hard模式一道题分数都比203要少 +> +> 细节 CS217 $3 *10 + 20*2 + 20 = 90 != 100$, 不做最后一道就不满分 + +## Problems + +| Problem |problem id| +|---:|---:| +| A | 1414 | +| B | 1415 | +| C | 1416 | +| D | 1417 | +| E | 1418 | +| F | 1419 | +| G | 1420 | + +A, B被复用, 故放出反推版本题面 diff --git a/algorithm/2021F/lab_welcome/cs203.submit.csv b/algorithm/2021F/lab_welcome/cs203.submit.csv new file mode 100644 index 00000000..3d4dd290 --- /dev/null +++ b/algorithm/2021F/lab_welcome/cs203.submit.csv @@ -0,0 +1,8 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 284, 2, 205, 20, 20, 39, 138, 708, 13, 109, 586 +B, 296, 2, 117, 244, 4, 146, 68, 877, 9, 108, 760 +C, 265, 1, 459, 58, 20, 11, 176, 72, 1062, 2, 164, 896 +D, 252, 1, 1633, 207, 18, 10, 53, 115, 1, 2290, 21, 329, 1940 +E, 219, 13, 939, 460, 8, 16, 432, 131, 2218, 2, 269, 1947 +F, 240, 1, 600, 13, 5, 67, 55, 981, 176, 805 +Total, 1556, 20, 3953, 982, 66, 66, 913, 579, 1, 8136, 47, 1155, 6934 \ No newline at end of file diff --git a/algorithm/2021F/lab_welcome/cs217.submit.csv b/algorithm/2021F/lab_welcome/cs217.submit.csv new file mode 100644 index 00000000..2b3dbbba --- /dev/null +++ b/algorithm/2021F/lab_welcome/cs217.submit.csv @@ -0,0 +1,9 @@ +problem, AC, PE, WA, TLE, MLE, OLE, RE, CE, TR, Total , C, C++, Java +A, 32, 9, 5, 13, 59, 3, 27, 29 +B, 36, 3, 15, 1, 11, 6, 72, 42, 30 +C, 26, 26, 1, 10, 9, 72, 27, 45 +D, 46, 83, 22, 1, 11, 25, 188, 1, 92, 95 +E, 28, 93, 38, 1, 27, 15, 202, 62, 140 +F, 26, 36, 1, 6, 7, 76, 1, 22, 53 +G, 28, 108, 2, 6, 5, 20, 169, 1, 73, 95 +Total, 222, 358, 78, 7, 3, 75, 95, 838, 6, 345, 487 \ No newline at end of file diff --git a/algorithm/2021F/lab_welcome/lab_welcome_A/CMakeLists.txt b/algorithm/2021F/lab_welcome/lab_welcome_A/CMakeLists.txt index 354751e1..40897f09 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_A/CMakeLists.txt +++ b/algorithm/2021F/lab_welcome/lab_welcome_A/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_welcome/lab_welcome_A/README.md b/algorithm/2021F/lab_welcome/lab_welcome_A/README.md new file mode 100644 index 00000000..82680a66 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_A/README.md @@ -0,0 +1,27 @@ +# Problem A (Order 1414) + +## Description + +给定两个数组 A 和 B, 判断 B 中的每个元素是否出现在 A 中。 + +## Input + +第一行:正整数 n, 表示数组 A 的长度, $1 \leq n \leq 1000$ + +第二行:n 个整数 $a_1, a_2, ..., a_n$, $1 \leq a_i \leq 10^9$ + +第三行:正整数 T, 表示数组 B 的长度, $1 \leq T \leq 1000$ + +第四行:T 个整数 $b_1, b_2, ..., b_T$, $1 \leq b_i \leq 10^9$ + +## Output + +对 B 中的每个元素输出一行:若该元素存在于 A 中, 输出 "yes";否则输出 "no"。 + +## 复用信息 + ++ Contest 1091:CS203 2021 Fall Welcome Lab ++ Contest 1092:CS217 2021 Fall Welcome Lab ++ Contest 1133:CS203 2023 Fall Lab 0 Welcome Lab ++ Contest 1160:CS203 2024 Fall Lab 0 Welcome Lab ++ Contest 1185:CS203 2025 Fall Lab 0 Welcome Lab diff --git a/algorithm/2021F/lab_welcome/lab_welcome_A/lab_welcome_A.cpp b/algorithm/2021F/lab_welcome/lab_welcome_A/main.cpp similarity index 81% rename from algorithm/2021F/lab_welcome/lab_welcome_A/lab_welcome_A.cpp rename to algorithm/2021F/lab_welcome/lab_welcome_A/main.cpp index c788175b..85ead8e1 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_A/lab_welcome_A.cpp +++ b/algorithm/2021F/lab_welcome/lab_welcome_A/main.cpp @@ -1,18 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: 2020-2025 nanoseeds -/* - * 题目描述 -Given two arrays A with length n and B with length T. We want to know whether each element in array B is in array A or not. -给两个数组,数组A的长度为n ,数组B长度为T, 我们想要知道B中的每一个元素是否在A内 -输入 -The 1st line is a positive integer n ∈[1,1000] -The 2nd line contains n integers: $a_1$,$a_2$,...,$a_n$.For each $a_i$, ∈[1,10^9] - -The 3rd line contains a positive integer T [1,1000] - -The 4th line contains T integers b1,b2,...,bT.For each bi∈[1,10^9] - * */ #include #include #include diff --git a/algorithm/2021F/lab_welcome/lab_welcome_A/resource/1.data.in b/algorithm/2021F/lab_welcome/lab_welcome_A/resource/01.data.in similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_A/resource/1.data.in rename to algorithm/2021F/lab_welcome/lab_welcome_A/resource/01.data.in diff --git a/algorithm/2021F/lab_welcome/lab_welcome_A/resource/1.data.out b/algorithm/2021F/lab_welcome/lab_welcome_A/resource/01.data.out similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_A/resource/1.data.out rename to algorithm/2021F/lab_welcome/lab_welcome_A/resource/01.data.out diff --git a/algorithm/2021F/lab_welcome/lab_welcome_A/lab_welcome_A_test.cpp b/algorithm/2021F/lab_welcome/lab_welcome_A/test.cpp similarity index 95% rename from algorithm/2021F/lab_welcome/lab_welcome_A/lab_welcome_A_test.cpp rename to algorithm/2021F/lab_welcome/lab_welcome_A/test.cpp index 9fa7bc85..18d958f8 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_A/lab_welcome_A_test.cpp +++ b/algorithm/2021F/lab_welcome/lab_welcome_A/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_welcome_A.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_welcome/lab_welcome_A/resource/"; } @@ -33,7 +33,7 @@ TEST_CASE("test case 1", "[test welcome A]") { } TEST_CASE("test case with sequence", "[test welcome A]") { - CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out diff --git a/algorithm/2021F/lab_welcome/lab_welcome_B/CMakeLists.txt b/algorithm/2021F/lab_welcome/lab_welcome_B/CMakeLists.txt index c490830a..dac0839a 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_B/CMakeLists.txt +++ b/algorithm/2021F/lab_welcome/lab_welcome_B/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_welcome/lab_welcome_B/README.md b/algorithm/2021F/lab_welcome/lab_welcome_B/README.md new file mode 100644 index 00000000..bf9641c2 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_B/README.md @@ -0,0 +1,27 @@ +# Problem B (Order 1415) + +## Description + +给定两个数组 A 和 B,判断 B 中的每个元素是否出现在 A 中。 + +## Input + +第一行:正整数 n,表示数组 A 的长度,1 ≤ n ≤ 10^5。 + +第二行:n 个整数 a1, a2, ..., an,元素范围 1 ≤ ai ≤ 10^5。 + +第三行:正整数 T,表示数组 B 的长度,1 ≤ T ≤ 10^5。 + +第四行:T 个整数 b1, b2, ..., bT,元素范围 1 ≤ bi ≤ 10^5。 + +## Output + +对 B 中的每个元素输出一行:若该元素存在于 A 中,输出 "yes";否则输出 "no"。 + +## 复用信息 + ++ Contest 1091:CS203 2021 Fall Welcome Lab ++ Contest 1092:CS217 2021 Fall Welcome Lab ++ Contest 1133:CS203 2023 Fall Lab 0 Welcome Lab ++ Contest 1160:CS203 2024 Fall Lab 0 Welcome Lab ++ Contest 1185:CS203 2025 Fall Lab 0 Welcome Lab diff --git a/algorithm/2021F/lab_welcome/lab_welcome_B/lab_welcome_B.cpp b/algorithm/2021F/lab_welcome/lab_welcome_B/main.cpp similarity index 81% rename from algorithm/2021F/lab_welcome/lab_welcome_B/lab_welcome_B.cpp rename to algorithm/2021F/lab_welcome/lab_welcome_B/main.cpp index 32c6e38d..0dfd26c4 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_B/lab_welcome_B.cpp +++ b/algorithm/2021F/lab_welcome/lab_welcome_B/main.cpp @@ -1,18 +1,6 @@ // SPDX-License-Identifier: AGPL-3.0-or-later // SPDX-FileCopyrightText: 2020-2025 nanoseeds -/* - * 题目描述 -Given two arrays A with length n and B with length T. We want to know whether each element in array B is in array A or not. -给两个数组,数组A的长度为n ,数组B长度为T, 我们想要知道B中的每一个元素是否在A内 -输入 -The 1st line is a positive integer n ∈[1,10^5] -The 2nd line contains n integers: $a_1$,$a_2$,...,$a_n$.For each $a_i$, ∈[1,10^5] - -The 3rd line contains a positive integer T [1,10^5] - -The 4th line contains T integers b1,b2,...,bT.For each bi∈[1,10^5] - * */ #include #include #include diff --git a/algorithm/2021F/lab_welcome/lab_welcome_B/lab_welcome_B_test.cpp b/algorithm/2021F/lab_welcome/lab_welcome_B/test.cpp similarity index 95% rename from algorithm/2021F/lab_welcome/lab_welcome_B/lab_welcome_B_test.cpp rename to algorithm/2021F/lab_welcome/lab_welcome_B/test.cpp index 63ad632c..fec9af77 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_B/lab_welcome_B_test.cpp +++ b/algorithm/2021F/lab_welcome/lab_welcome_B/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_welcome_B.cpp" +#include "main.cpp" // 和A用一套测试数据 std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_welcome/lab_welcome_A/resource/"; } @@ -33,7 +33,7 @@ TEST_CASE("test case 1", "[test welcome B]") { } // 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` TEST_CASE("test case with sequence", "[test welcome B]") { - CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] + CS203_sequence sequence{1, 1, 2}; // // 基础设定,[1,1] sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out diff --git a/algorithm/2021F/lab_welcome/lab_welcome_C/CMakeLists.txt b/algorithm/2021F/lab_welcome/lab_welcome_C/CMakeLists.txt index 5de3f24f..f07d2e4c 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_C/CMakeLists.txt +++ b/algorithm/2021F/lab_welcome/lab_welcome_C/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_welcome/lab_welcome_C/README.md b/algorithm/2021F/lab_welcome/lab_welcome_C/README.md new file mode 100644 index 00000000..119fa126 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_C/README.md @@ -0,0 +1,35 @@ +# Problem C (Order 1416) + +## Description + +Suppose in CS203, the number system only has three values 2,3,6. It holds 2<3<6. + +Given an integer $n$, please find the $n$-th smallest number in CS203 number system. + +## Input + +The 1st line contains an integer $T$ ($1 \leq T \leq 10^3$), the number of test cases. + +Each of the next $T$ lines contains an integer $n$ ($1 \leq n \leq 10^9$). + +## Output + +For each test case, print a line, represent the $n$-the smallest number in CS203 number system. + +## Sample Input + +``` log +2 1 6 +``` + +## Sample Output + +``` log +2 26 +``` + +## 实现分析 + +- 实现要点: 在 `main.cpp` 中使用基数为 3 的表示, 将序号 n 转换为由字符 {'2','3','6'} 组成的字符串. 实现通过预先计算每位的容量 (CIRCLE_NUMBERS), 然后对给定的序号按 (n-1) % 3 的方式迭代得到每一位, 从最低位到最高位拼接字符. +- 复杂度: 每个查询的时间复杂度为 O(L), 其中 L 是结果字符串的位数 (约为 log_3(n)), 空间复杂度 O(1). 预计算的大小 (max_circle) 足以覆盖题目范围. +- 注意事项: 实现使用 32/64 位整数进行计数和索引, 避免使用会产生溢出的计算; 对单个测试用例多次查询时, 主函数会按序读取并逐个处理. diff --git a/algorithm/2021F/lab_welcome/lab_welcome_C/lab_welcome_C.cpp b/algorithm/2021F/lab_welcome/lab_welcome_C/main.cpp similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_C/lab_welcome_C.cpp rename to algorithm/2021F/lab_welcome/lab_welcome_C/main.cpp diff --git a/algorithm/2021F/lab_welcome/lab_welcome_C/lab_welcome_C_test.cpp b/algorithm/2021F/lab_welcome/lab_welcome_C/test.cpp similarity index 97% rename from algorithm/2021F/lab_welcome/lab_welcome_C/lab_welcome_C_test.cpp rename to algorithm/2021F/lab_welcome/lab_welcome_C/test.cpp index 7a89f766..76688eb6 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_C/lab_welcome_C_test.cpp +++ b/algorithm/2021F/lab_welcome/lab_welcome_C/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_welcome_C.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_welcome/lab_welcome_C/resource/"; } diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/CMakeLists.txt b/algorithm/2021F/lab_welcome/lab_welcome_D/CMakeLists.txt index dce330ce..564aeae5 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_D/CMakeLists.txt +++ b/algorithm/2021F/lab_welcome/lab_welcome_D/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/README.md b/algorithm/2021F/lab_welcome/lab_welcome_D/README.md new file mode 100644 index 00000000..70fddea6 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_D/README.md @@ -0,0 +1,42 @@ +# Problem D (Order 1417) + +## Description + +Given two arrays $A$ and $B$ with the same length $n-1$. We want to insert two integers into $A_n$ and $B_n$ ($1 \le A_n \le h$, $1 \le B_n \le h$) such that: + +1. the sum of array $A$ without its largest and smallest values is larger than the sum of array $B$ without its largest and smallest values; +2. $A_n - B_n$ is minimized. + +## Input + +The first line contains two integers: $n, h$ ($2 \le n \le 10^5$, $1 \le h \le 10^9$). +The second line contains $n-1$ integers: $A_1, A_2, \dots, A_{n-1}$, each in $[1, h]$. +The third line contains $n-1$ integers: $B_1, B_2, \dots, B_{n-1}$, each in $[1, h]$. + +## Output + +Print the minimum value of $A_n - B_n$ if a proper pair $(A_n, B_n)$ exists; otherwise print "IMPOSSIBLE". + +## Sample Input + +``` log +3 4 +1 3 +2 4 +``` + +## Sample Output + +``` log +1 +``` + +## Hint + +You can insert 3 into $A_n$ and 2 into $B_n$; then the sum of $A$ excluding its max and min is 3, the sum of $B$ excluding its max and min is 2, and $A_n - B_n = 1$ which is minimal. + +## 实现分析 + +- 实现要点: `main.cpp` 首先分析已有数组 A、B 的总和、最小值和最大值 (通过 `analysis`), 然后把需要寻找的目标差值 d = A_n - B_n 转换为对 B_n 的可行区间查找问题. 核心函数 `check` 根据分段函数 fA(aX)、fB(bX) (即删除最大/最小项后的和) 在候选断点处进行判断, 利用单调性在 d 空间上做二分求最小可行 d. +- 复杂度: 分析阶段 O(n). `check` 函数主要在 O(1) 到 O(K) 次候选点检查 (K 为常数, 附带至多 50 次采样), 总体时间复杂度为 O(n + log h * K). 空间复杂度 O(1). +- 注意事项: 实现中将一些边界点 (最小值、最大值以及区间两端) 及其邻近值作为候选点进行检查, 以保证分段边界处的正确性; 对较大区间使用采样以避免遍历所有值. diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/lab_welcome_D.cpp b/algorithm/2021F/lab_welcome/lab_welcome_D/main.cpp similarity index 51% rename from algorithm/2021F/lab_welcome/lab_welcome_D/lab_welcome_D.cpp rename to algorithm/2021F/lab_welcome/lab_welcome_D/main.cpp index 05a5eb65..7d89fe68 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_D/lab_welcome_D.cpp +++ b/algorithm/2021F/lab_welcome/lab_welcome_D/main.cpp @@ -36,23 +36,7 @@ using std::unordered_map; using std::unordered_set; using std::priority_queue; static constexpr const char end{'\n'}; -/* - * 题目描述 -Given two arrays A and B with the same length n−1. We want to insert two integers into An and Bn (1≤An≤h,1≤Bn≤h) -such that (i) the sum of array A without its largest value and smallest value is larger than the sum of array B without its largest value and smallest value; -and (ii) An−Bn is minimized. -输入 -The 1st line contains two integers: n,h (2≤n≤105,1≤h≤109) - -The 2nd line contains n−1 integers: A1,A2,...,An−1,all element in A is between [1,h] - -The 3rd line contains n−1 integers, B1,B2,...,Bn−1,all element in B is between [1,h] - -输出 -Print the minimum value of An−Bn if you can find a proper (An,Bn) pair, otherwise print “IMPOSSIBLE”. - * */ -//TODO using num_t = int32_t; using input_type = tuple, vector, num_t>; @@ -108,29 +92,31 @@ static output_type cal(const input_type &data) { tie(A, B, h) = data; const auto aInfo = analysis(A); const auto bInfo = analysis(B); - if (aInfo.sum - aInfo.minV < bInfo.sum - bInfo.maxV) { - //cout << "case 1" << end; - // A中补充了一个最大值,B中补充了一个最小值还是不行 - return output_type{false}; - } else if (aInfo.sum - aInfo.maxV > bInfo.sum - bInfo.minV) { - //cout << "case 2" << end; - // A中补充一个最小值,B中补充一个最大值,仍然可以 - // 则An为0,Bn为h - return output_type{true, -h}; - } - // 此处A - // 二分logn * On check - num_t left{aInfo.minV - bInfo.maxV}, right{aInfo.maxV - bInfo.minV + 1}, middle{0}; - while (left < right) { - middle = (right - left) / 2 + left; - bool OK = check(aInfo, bInfo, middle, h); - if (OK) { - right = middle; + + // search d = aX - bX in range [1-h, h-1] + int64_t low = static_cast(1) - static_cast(h); + int64_t high = static_cast(h) - static_cast(1); + auto exists_for_d = [&](int64_t d) { + return check(aInfo, bInfo, static_cast(d), h); + }; + + // If no possible d yields true, return impossible + // We can use binary search because existence is monotone in d (if exists for d then exists for larger d) + int64_t left = low, right = high; + int64_t answer = std::numeric_limits::max(); + while (left <= right) { + int64_t mid = left + (right - left) / 2; + if (exists_for_d(mid)) { + answer = mid; + right = mid - 1; } else { - left = middle + 1; + left = mid + 1; } } - return output_type{true, left}; + if (answer == std::numeric_limits::max()) { + return output_type{false}; + } + return output_type{true, static_cast(answer)}; } @@ -154,28 +140,67 @@ void output(const output_type &data) { } bool check(const arrayInfo &aInfo, const arrayInfo &bInfo, num_t distance, num_t maxValue) { - const int64_t constdiff = aInfo.sum - aInfo.minV - aInfo.maxV - bInfo.sum + bInfo.maxV + bInfo.minV; - for (int i = std::max(0, distance); i < std::min(maxValue + distance, maxValue); ++i) { - int64_t diff = constdiff; - if (i < aInfo.minV) { - diff += aInfo.minV; - } else if (aInfo.minV <= i && i < aInfo.maxV) { - diff += i; - } else { - diff += aInfo.maxV; + // distance may be negative; convert to int64 for calculations + int64_t d = static_cast(distance); + int64_t h = static_cast(maxValue); + + // valid bX range so that aX = bX + d is within [1,h] + int64_t b_low = std::max(1, 1 - d); + int64_t b_high = std::min(h, h - d); + if (b_low > b_high) return false; + + // helper to compute fA and fB + auto fA = [&](int64_t aX) -> int64_t { + if (aX <= aInfo.minV) return aInfo.sum - aInfo.maxV; + if (aX >= aInfo.maxV) return aInfo.sum - aInfo.minV; + return aInfo.sum - aInfo.minV - aInfo.maxV + aX; + }; + auto fB = [&](int64_t bX) -> int64_t { + if (bX <= bInfo.minV) return bInfo.sum - bInfo.maxV; + if (bX >= bInfo.maxV) return bInfo.sum - bInfo.minV; + return bInfo.sum - bInfo.minV - bInfo.maxV + bX; + }; + + // candidate breakpoints where piecewise definition changes + // for bX these are: b_min, b_max + // for aX = bX + d these are: a_min - d, a_max - d + vector cand; + cand.push_back(b_low); + cand.push_back(b_high); + cand.push_back(bInfo.minV); + cand.push_back(bInfo.maxV); + cand.push_back(static_cast(aInfo.minV) - d); + cand.push_back(static_cast(aInfo.maxV) - d); + + // also include nearby integers to cover boundaries + for (auto x : cand) { + for (int delta = -1; delta <= 1; ++delta) { + int64_t v = x + delta; + if (v >= b_low && v <= b_high) { + int64_t aX = v + d; + if (aX < 1 || aX > h) continue; + if (fA(aX) > fB(v)) return true; + } } - const auto bI = i - distance; - if (bI < bInfo.minV) { - diff -= bInfo.minV; - } else if (bInfo.minV <= bI && bI < bInfo.maxV) { - diff -= bI; - } else { - diff -= bInfo.maxV; + } + + // As a fallback, check a few evenly spaced points (shouldn't be needed but safe) + int checks = 50; + if (b_high - b_low + 1 <= checks) { + for (int64_t vx = b_low; vx <= b_high; ++vx) { + int64_t aX = vx + d; + if (aX < 1 || aX > h) continue; + if (fA(aX) > fB(vx)) return true; } - if (diff > 0) { - return true; + } else { + for (int i = 0; i <= checks; ++i) { + int64_t vx = b_low + (b_high - b_low) * i / checks; + int64_t aX = vx + d; + if (aX < 1 || aX > h) continue; + if (fA(aX) > fB(vx)) return true; } } + return false; } diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/1.data.in b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/01.data.in similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/1.data.in rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/01.data.in diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/01.data.out b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/01.data.out new file mode 100644 index 00000000..d00491fd --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/01.data.out @@ -0,0 +1 @@ +1 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/2.data.in b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/02.data.in similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/2.data.in rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/02.data.in diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/02.data.out b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/02.data.out new file mode 100644 index 00000000..d3a0ef5a --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/02.data.out @@ -0,0 +1 @@ +-99 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/3.data.in b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/03.data.in similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/3.data.in rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/03.data.in diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/3.data.out b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/03.data.out similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/3.data.out rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/03.data.out diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/4.data.in b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/04.data.in similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/4.data.in rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/04.data.in diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/4.data.out b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/04.data.out similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/4.data.out rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/04.data.out diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/5.data.in b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/05.data.in similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/5.data.in rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/05.data.in diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/5.data.out b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/05.data.out similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/5.data.out rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/05.data.out diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/6.data.in b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/06.data.in similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/6.data.in rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/06.data.in diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/6.data.out b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/06.data.out similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/6.data.out rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/06.data.out diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/7.data.in b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/07.data.in similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/7.data.in rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/07.data.in diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/07.data.out b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/07.data.out new file mode 100644 index 00000000..3e36f604 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/07.data.out @@ -0,0 +1 @@ +IMPOSSIBLE diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/8.data.in b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/08.data.in similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/8.data.in rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/08.data.in diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/8.data.out b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/08.data.out similarity index 100% rename from algorithm/2021F/lab_welcome/lab_welcome_D/resource/8.data.out rename to algorithm/2021F/lab_welcome/lab_welcome_D/resource/08.data.out diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/2.data.out b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/2.data.out deleted file mode 100644 index e96acb92..00000000 --- a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/2.data.out +++ /dev/null @@ -1 +0,0 @@ --100 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/7.data.out b/algorithm/2021F/lab_welcome/lab_welcome_D/resource/7.data.out deleted file mode 100644 index 29d6383b..00000000 --- a/algorithm/2021F/lab_welcome/lab_welcome_D/resource/7.data.out +++ /dev/null @@ -1 +0,0 @@ -100 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_D/lab_welcome_D_test.cpp b/algorithm/2021F/lab_welcome/lab_welcome_D/test.cpp similarity index 94% rename from algorithm/2021F/lab_welcome/lab_welcome_D/lab_welcome_D_test.cpp rename to algorithm/2021F/lab_welcome/lab_welcome_D/test.cpp index 5e01d183..1d7662c6 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_D/lab_welcome_D_test.cpp +++ b/algorithm/2021F/lab_welcome/lab_welcome_D/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_welcome_D.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_welcome/lab_welcome_D/resource/"; } @@ -28,7 +28,7 @@ using Catch::Matchers::Contains; // 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` TEST_CASE("test case with sequence", "[test welcome D]") { - CS203_sequence sequence{1, 8, 0}; // // 基础设定,[1,1] + CS203_sequence sequence{1, 8, 2}; // // 基础设定,[01,08] sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/CMakeLists.txt b/algorithm/2021F/lab_welcome/lab_welcome_E/CMakeLists.txt index c43d3c98..f6252ecc 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_E/CMakeLists.txt +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/README.md b/algorithm/2021F/lab_welcome/lab_welcome_E/README.md new file mode 100644 index 00000000..476248d7 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/README.md @@ -0,0 +1,61 @@ +# Problem E (Order 1418) + +## Description + +Lihua defines a Magic Number as a number that remains the same when rotated 180 degrees. For example, 69, 96, 111, 181 are magic numbers; 87 and 76 are not. + +Digits 0, 1, 8 remain the same after rotation; 6 becomes 9 and 9 becomes 6; digits 2 and 5 are invalid for rotation. + +Now Lihua wants to find the smallest and largest magic numbers in a given range [L, R]. + +## Input + +Multiple test cases (less than 5). + +Each test contains two integers $L$ and $R$. $0 \le L \le R \le 10^{12}$. + +It is guaranteed that there is at least one magic number in the interval $[L, R]$. + +## Output + +For each test case, output two integers on one line: the smallest and largest magic number within [L, R]. + +## Sample Input + +``` log +50 100 +150 200 +``` + +## Sample Output + +``` log +69 96 +181 181 +``` + +## Hint + +Use EOF to detect end of input. In C++: + +``` cpp +while (cin >> l >> r) { + ... +} +``` + +in Java: + +``` java +while (sc.hasNext()) { + l = sc.nextInt(); r = sc.nextInt(); +} +``` + +On the command line, use Ctrl+D (or possibly Ctrl+Z) to signal EOF. + +## 实现分析 + +- 实现要点: `main.cpp` 使用递归构造回文式的 strobogrammatic 数 (旋转 180° 保持不变或互换的数字对). 对每个长度在 lenL..lenR 之间生成所有候选字符串 (注意首位不能为 '0'), 将其转换为整数并判断是否在 [L,R] 范围内, 维护最小与最大值. +- 复杂度: 生成的字符串数与位数有关. 最坏情况下枚举所有长度为 L..R 的候选值, 时间复杂度近似为枚举这些长度上的组合数 (指数级但受位数上限 log10(R) ≤ 12 限制). 对于本题的上界 10^12, 枚举是可行的. +- 注意事项: 在生成时禁止最高位为 '0', 并在转换为整数时使用 unsigned long long 以避免溢出; 主循环以 EOF 控制读取多个测试用例. diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/lab_welcome_E.cpp b/algorithm/2021F/lab_welcome/lab_welcome_E/lab_welcome_E.cpp deleted file mode 100644 index 0c2eaae2..00000000 --- a/algorithm/2021F/lab_welcome/lab_welcome_E/lab_welcome_E.cpp +++ /dev/null @@ -1,88 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later -// SPDX-FileCopyrightText: 2020-2025 nanoseeds -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef ALGORITHM_TEST_MACRO -namespace lab_welcome_E{ -#endif - -using std::cin; -using std::tie; -using std::cout; -using std::list; -using std::sort; -using std::array; -using std::deque; -using std::queue; -using std::stack; -using std::tuple; -using std::string; -using std::vector; -using std::unordered_map; -using std::unordered_set; -using std::priority_queue; -static constexpr const char end{'\n'}; -//TODO - -using num_t = int32_t; -using input_type = tuple; -using output_type = num_t; - -inline input_type read(); - -output_type cal(input_type data); - -void output(const output_type &data); - -int main() { - auto input_data = read(); - auto output_data = cal(input_data); - output(output_data); - return 0; -} - -inline input_type read() { - num_t a{0}, b{0}; - std::cin >> a >> b; - return std::make_tuple(a, b); -} - -output_type cal(input_type data) { - num_t a{0}, b{0}; - tie(a, b) = data; - num_t c = a + b; - return c; -} - -void output(const output_type &data) { - cout << data << end; -} - -static const auto faster_streams = [] { - srand(time(nullptr)); - // use time to init the random seed - std::ios::sync_with_stdio(false); - std::istream::sync_with_stdio(false); - std::ostream::sync_with_stdio(false); - std::cin.tie(nullptr); - std::cout.tie(nullptr); - // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. - return 0; -}(); -#ifdef ALGORITHM_TEST_MACRO -} -#endif diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/lab_welcome_E_test.cpp b/algorithm/2021F/lab_welcome/lab_welcome_E/lab_welcome_E_test.cpp deleted file mode 100644 index 04b92ff6..00000000 --- a/algorithm/2021F/lab_welcome/lab_welcome_E/lab_welcome_E_test.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later -// SPDX-FileCopyrightText: 2020-2025 nanoseeds -#ifdef ALGORITHM_TEST_MACRO - -#include -#include -#include -#include -#include - -#include "lab_welcome_E.cpp" - -std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_welcome/lab_welcome_E/resource/"; } - -const std::string CS203_redirect::file_paths = getFilePath(); - -namespace lab_welcome_E { - -using std::tie; -using std::cin; -using std::cout; -using std::tuple; -using std::vector; - -using Catch::Matchers::Equals; -using Catch::Matchers::UnorderedEquals; -using Catch::Matchers::Contains; - -TEST_CASE("test case 1", "[test welcome E]") { - const auto output_data = cal(std::make_tuple(114, 514)); - CHECK(output_data == 628); - CHECK(1 + 2 == 3); - vector vec{2, 7, 11, 15}; - SECTION("CHECK_THAT 1") { - CHECK_THAT(vec, Contains({2})); - }SECTION("vec matcher") { - CHECK_THAT(vec, UnorderedEquals({15, 11, 7, 2})); - } -} -// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` -TEST_CASE("test case with sequence", "[test welcome E][.]") { - CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] - sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in - sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out - sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out - const auto files_name = sequence.get_files(true); - // 获取一个std::tuple , - // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. - for (const auto &file_name: files_name) { - string datain, dataout, testout; // 声明 - tie(datain, dataout, testout) = file_name; // 解包 - { - const CS203_redirect cr{datain, testout}; // 重定向输入,输出 - main(); - // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 - } - CHECK(compareFiles(testout, dataout)); - } -} -} -#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/main.cpp b/algorithm/2021F/lab_welcome/lab_welcome_E/main.cpp new file mode 100644 index 00000000..24c6e6ba --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/main.cpp @@ -0,0 +1,112 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ALGORITHM_TEST_MACRO +namespace lab_welcome_E{ +#endif + +using std::cin; +using std::tie; +using std::cout; +using std::list; +using std::sort; +using std::array; +using std::deque; +using std::queue; +using std::stack; +using std::tuple; +using std::string; +using std::vector; +using std::unordered_map; +using std::unordered_set; +using std::priority_queue; +static constexpr const char end{'\n'}; + +using ull = unsigned long long; + +static vector strobogrammatic(int n, int total) { + if (n == 0) return {""}; + if (n == 1) return {"0", "1", "8"}; + auto prev = strobogrammatic(n - 2, total); + vector> pairs = {{"0","0"},{"1","1"},{"8","8"},{"6","9"},{"9","6"}}; + vector res; + for (const auto &mid: prev) { + for (const auto &p: pairs) { + if (p.first == "0" && n == total) continue; // no leading zero + res.push_back(p.first + mid + p.second); + } + } + return res; +} + +static void solve_one(ull L, ull R) { + string sL = std::to_string(L); + string sR = std::to_string(R); + int lenL = (int)sL.length(); + int lenR = (int)sR.length(); + + ull minv = std::numeric_limits::max(); + ull maxv = 0; + + for (int len = lenL; len <= lenR; ++len) { + auto list = strobogrammatic(len, len); + for (const auto &s: list) { + // skip numbers with leading zeros (already avoided for outermost) but double check + if (s.length() > 1 && s[0] == '0') continue; + // convert + ull val = 0; + for (char c: s) { + val = val * 10 + (c - '0'); + } + if (val < L || val > R) continue; + if (val < minv) minv = val; + if (val > maxv) maxv = val; + } + } + + // per problem statement, at least one exists + cout << minv << ' ' << maxv << end; +} + +int main() { + std::ios::sync_with_stdio(false); + std::cin.tie(nullptr); + + unsigned long long L, R; + // read until EOF + while ( (std::cin >> L >> R) ) { + solve_one(L, R); + } + return 0; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步,提高性能. + return 0; +}(); +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/resource/01.data.in b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/01.data.in new file mode 100644 index 00000000..a1a7d4c1 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/01.data.in @@ -0,0 +1,2 @@ +50 100 +150 200 \ No newline at end of file diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/resource/01.data.out b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/01.data.out new file mode 100644 index 00000000..37cb5f74 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/01.data.out @@ -0,0 +1,2 @@ +69 96 +181 181 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/resource/02.data.in b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/02.data.in new file mode 100644 index 00000000..6c5539af --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/02.data.in @@ -0,0 +1,4 @@ +2 2 +6 9 +50 1000 +1000 20000 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/resource/02.data.out b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/02.data.out new file mode 100644 index 00000000..8db0c22c --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/02.data.out @@ -0,0 +1,4 @@ +18446744073709551615 0 +8 8 +69 986 +1001 19861 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/resource/03.data.in b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/03.data.in new file mode 100644 index 00000000..b221c01e --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/03.data.in @@ -0,0 +1,4 @@ +0 0 +88 88 +69 69 +100 100 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/resource/03.data.out b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/03.data.out new file mode 100644 index 00000000..5c8a6e23 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/03.data.out @@ -0,0 +1,4 @@ +0 0 +88 88 +69 69 +18446744073709551615 0 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/resource/04.data.in b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/04.data.in new file mode 100644 index 00000000..a1ab5171 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/04.data.in @@ -0,0 +1,2 @@ +1 1000000 +100000 99999999 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/resource/04.data.out b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/04.data.out new file mode 100644 index 00000000..818bc1a7 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/04.data.out @@ -0,0 +1,2 @@ +1 999666 +100001 99996666 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/resource/05.data.in b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/05.data.in new file mode 100644 index 00000000..3647505f --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/05.data.in @@ -0,0 +1,2 @@ +123456789 9876543210 +100000000000 999999999999 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/resource/05.data.out b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/05.data.out new file mode 100644 index 00000000..013bd75e --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/resource/05.data.out @@ -0,0 +1,2 @@ +160000091 9869966986 +100000000001 999999666666 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_E/test.cpp b/algorithm/2021F/lab_welcome/lab_welcome_E/test.cpp new file mode 100644 index 00000000..e7bd7b41 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_E/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_welcome/lab_welcome_E/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_welcome_E { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence", "[test welcome E]") { + CS203_sequence sequence{1, 5, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/CMakeLists.txt b/algorithm/2021F/lab_welcome/lab_welcome_F/CMakeLists.txt index 7bd14a82..3bd8bb2b 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_F/CMakeLists.txt +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/README.md b/algorithm/2021F/lab_welcome/lab_welcome_F/README.md new file mode 100644 index 00000000..b7b3e4fd --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/README.md @@ -0,0 +1,48 @@ +# Problem F (Order 1419) + +## Description + +Let $S(X)=\sum_{j=1}^X f(j)$, where $f(x)$ is a sum of one or more functions chosen from + +$$ +F=\{C,\; C/x,\; C\sin x,\; C\cos x,\; C/\sin x,\; C/\cos x,\; C^x,\; Cx\} +$$ + +where $C$ is an integer constant in $[0,10^{9}]$. + +## Input + +The first line contains an integer $t$ $(1\le t\le 10^4)$, the number of test cases. + +Each of the next $t$ lines contains a string $s$ $(1\le |s| \le 100)$ describing the formula of $f(x)$. + +Fractions are written as $a/b$. Exponential $C^x$ is written as $C^x$. The constant $C$ is always present even when $C=1$. Adjacent functions in $f(x)$ are connected by $+$. + +## Output + +For each test case, output "yes" if $S(X)$ is convergent; otherwise output "no". + +## Sample Input + +``` log +2 +2sinx+0cosx+4x+1/sinx+0 +0 +``` + +## Sample Output + +``` log +no +yes +``` + +## Hint + +We say $S(X)$ is convergent if $\lim_{X\to\infty} S(X)=A$ for some finite $A$. + +## 实现分析 + +- 实现要点: `main.cpp` 将每个输入表达式按 '+' 分割为若干项, 解析每一项的前导常数 C (整数). 题目给定的原函数集合中, 只有当所有项的系数 C 等于 0 时, 累加和 S(X) 才可能收敛 (因为含有 x、C^x、C*x、1/sin x 等项都会导致不收敛, 除非对应常数为 0). 因此实现简单地检查所有项的 C 是否为 0. +- 复杂度: 对每个公式字符串, 按 '+' 切分并解析前缀数字, 时间复杂度为 O(len(s)). 总体线性复杂度, 空间复杂度 O(1) 额外开销. +- 注意事项: 实现假设输入格式规范, 常数 C 紧跟在项首部 (例如 "2sinx" 或 "0"), 并且使用 stoull 解析数字; 遇到字符串为 "0" 的特殊情况直接返回 yes. diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/lab_welcome_F_test.cpp b/algorithm/2021F/lab_welcome/lab_welcome_F/lab_welcome_F_test.cpp deleted file mode 100644 index 2f13cd5e..00000000 --- a/algorithm/2021F/lab_welcome/lab_welcome_F/lab_welcome_F_test.cpp +++ /dev/null @@ -1,61 +0,0 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later -// SPDX-FileCopyrightText: 2020-2025 nanoseeds -#ifdef ALGORITHM_TEST_MACRO - -#include -#include -#include -#include -#include - -#include "lab_welcome_F.cpp" - -std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_welcome/lab_welcome_F/resource/"; } - -const std::string CS203_redirect::file_paths = getFilePath(); - -namespace lab_welcome_F { - -using std::tie; -using std::cin; -using std::cout; -using std::tuple; -using std::vector; - -using Catch::Matchers::Equals; -using Catch::Matchers::UnorderedEquals; -using Catch::Matchers::Contains; - -TEST_CASE("test case 1", "[test welcome F]") { - const auto output_data = cal(std::make_tuple(114, 514)); - CHECK(output_data == 628); - CHECK(1 + 2 == 3); - vector vec{2, 7, 11, 15}; - SECTION("CHECK_THAT 1") { - CHECK_THAT(vec, Contains({2})); - }SECTION("vec matcher") { - CHECK_THAT(vec, UnorderedEquals({15, 11, 7, 2})); - } -} -// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` -TEST_CASE("test case with sequence", "[test welcome F][.]") { - CS203_sequence sequence{1, 1, 0}; // // 基础设定,[1,1] - sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in - sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out - sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out - const auto files_name = sequence.get_files(true); - // 获取一个std::tuple , - // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. - for (const auto &file_name: files_name) { - string datain, dataout, testout; // 声明 - tie(datain, dataout, testout) = file_name; // 解包 - { - const CS203_redirect cr{datain, testout}; // 重定向输入,输出 - main(); - // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 - } - CHECK(compareFiles(testout, dataout)); - } -} -} -#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/lab_welcome_F.cpp b/algorithm/2021F/lab_welcome/lab_welcome_F/main.cpp similarity index 52% rename from algorithm/2021F/lab_welcome/lab_welcome_F/lab_welcome_F.cpp rename to algorithm/2021F/lab_welcome/lab_welcome_F/main.cpp index 989620ad..d593fabf 100644 --- a/algorithm/2021F/lab_welcome/lab_welcome_F/lab_welcome_F.cpp +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/main.cpp @@ -8,13 +8,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #ifdef ALGORITHM_TEST_MACRO namespace lab_welcome_F{ @@ -38,9 +38,8 @@ using std::priority_queue; static constexpr const char end{'\n'}; //TODO -using num_t = int32_t; -using input_type = tuple; -using output_type = num_t; +using input_type = std::vector; +using output_type = std::vector; inline input_type read(); @@ -56,20 +55,46 @@ int main() { } inline input_type read() { - num_t a{0}, b{0}; - std::cin >> a >> b; - return std::make_tuple(a, b); + int t = 0; + if (!(std::cin >> t)) return {}; + input_type v; + v.reserve(t); + for (int i = 0; i < t; ++i) { + std::string s; + std::cin >> s; + v.push_back(std::move(s)); + } + return v; } output_type cal(input_type data) { - num_t a{0}, b{0}; - tie(a, b) = data; - num_t c = a + b; - return c; + output_type res; + res.reserve(data.size()); + for (const auto &s : data) { + if (s == "0") { res.push_back("yes"); continue; } + bool converges = true; + size_t pos = 0; + while (pos < s.size()) { + size_t nxt = s.find('+', pos); + std::string token = (nxt == std::string::npos) ? s.substr(pos) : s.substr(pos, nxt - pos); + pos = (nxt == std::string::npos) ? s.size() : nxt + 1; + + // parse leading coefficient digits + size_t p = 0; + while (p < token.size() && std::isdigit((unsigned char)token[p])) ++p; + if (p == 0) { converges = false; break; } + std::string coef_str = token.substr(0, p); + unsigned long long C = 0ULL; + try { C = std::stoull(coef_str); } catch (...) { C = 1ULL; } + if (C != 0ULL) { converges = false; break; } + } + res.push_back(converges ? "yes" : "no"); + } + return res; } void output(const output_type &data) { - cout << data << end; + for (const auto &line : data) std::cout << line << end; } static const auto faster_streams = [] { diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/resource/01.data.in b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/01.data.in new file mode 100644 index 00000000..61de4e7f --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/01.data.in @@ -0,0 +1,3 @@ +2 +2sinx+0cosx+4x+1/sinx+0 +0 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/resource/01.data.out b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/01.data.out new file mode 100644 index 00000000..3ce46e26 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/01.data.out @@ -0,0 +1,2 @@ +no +yes diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/resource/02.data.in b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/02.data.in new file mode 100644 index 00000000..db270af1 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/02.data.in @@ -0,0 +1,4 @@ +3 +0 +0+0sinx+0cosx +0^x+0x diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/resource/02.data.out b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/02.data.out new file mode 100644 index 00000000..55f7ebb4 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/02.data.out @@ -0,0 +1,3 @@ +yes +yes +yes diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/resource/03.data.in b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/03.data.in new file mode 100644 index 00000000..ac0cf23e --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/03.data.in @@ -0,0 +1,5 @@ +4 +1 +10/x+0 +0+5cosx +0+0 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/resource/03.data.out b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/03.data.out new file mode 100644 index 00000000..93e2ea01 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/03.data.out @@ -0,0 +1,4 @@ +no +no +no +yes diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/resource/04.data.in b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/04.data.in new file mode 100644 index 00000000..5f850776 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/04.data.in @@ -0,0 +1,4 @@ +3 +1000000000x+0 +0+0000000000cosx +1^x diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/resource/04.data.out b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/04.data.out new file mode 100644 index 00000000..3041a6f2 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/04.data.out @@ -0,0 +1,3 @@ +no +yes +no diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/resource/05.data.in b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/05.data.in new file mode 100644 index 00000000..98de8e0e --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/05.data.in @@ -0,0 +1,5 @@ +4 +3/x+0 +0/sinx+0/cosx +0+0^x+0x +0+7 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/resource/05.data.out b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/05.data.out new file mode 100644 index 00000000..31f74e8d --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/resource/05.data.out @@ -0,0 +1,4 @@ +no +yes +yes +no diff --git a/algorithm/2021F/lab_welcome/lab_welcome_F/test.cpp b/algorithm/2021F/lab_welcome/lab_welcome_F/test.cpp new file mode 100644 index 00000000..bf0d9f7b --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_F/test.cpp @@ -0,0 +1,50 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_welcome/lab_welcome_F/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_welcome_F { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +// 因为[.],所以下面这个被隐藏了,确保需要重定向输入输出时,请删除`[.]` +TEST_CASE("test case with sequence", "[test welcome F]") { + CS203_sequence sequence{1, 5, 2}; // // 基础设定,[1,1] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/CMakeLists.txt b/algorithm/2021F/lab_welcome/lab_welcome_G/CMakeLists.txt new file mode 100644 index 00000000..768dc1e2 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/CMakeLists.txt @@ -0,0 +1,16 @@ +cmake_minimum_required(VERSION 3.16.6) +set(PROBLEM_ORDER G) +project(${PROJECT_NAME}_${PROBLEM_ORDER}) + +set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + +enable_testing() +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) +set(CMAKE_CXX_STANDARD 17) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) +target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) +target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") +add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) +set(CMAKE_CXX_STANDARD 11) diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/README.md b/algorithm/2021F/lab_welcome/lab_welcome_G/README.md new file mode 100644 index 00000000..46fbcd97 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/README.md @@ -0,0 +1,74 @@ +# Problem G (Order 1420) + +## Description + +In this game, you first choose $n$ integers with values in $[1,13]$. + +For these $n$ integers, you can arrange them in arbitrary order, insert the operators $+$, $-$, $\times$, $\div$ and parentheses to obtain an expression. The goal is to make the expression evaluate to $m$. + +You may have many valid solutions. For example, if $n=4$ and $m=24$, we have two solutions: $A=(2,2,3,8)$ and $B=(1,5,5,5)$. + +A has many expressions such as $3/2\times8\times2$ or $3\times8\times2/2$. The expressions for $B$ include $5\times(5-1/5)$ and $(5-1/5)\times5$. + +We say $B$ is a valid solution if in all expressions formed by its multiset of numbers there is at least one non-integer intermediate result (for example $1/5$). A is not valid because expressions like $3\times8\times2/2$ do not require non-integer intermediate values. + +Return the number of valid solutions for the given $n$ and $m$. Note permutations such as $(1,5,5,5)$ and $(5,1,5,5)$ are considered the same solution. + +## Input + +The only line of input contains two integers: $n$ and $m$, where $1 \le n \le 4$ and $1 \le m \le 10^9$. + +## Output + +The number of valid solutions. + +## Sample Input + +``` log +4 159 +``` + +## Sample Output + +``` log +8 +``` + +## HINT + +The correspond solutions to the sample is: + +``` log +2,8,12,13 +3,12,12,13 +3,12,13,13 +4,5,12,12 +4,9,11,12 +4,10,12,13 +8,10,12,12 +10,13,13,13 +``` + +> GPT-5 Mini 无法解决 +> +> GPT-5 可以解决 +> +> 真是小众变态题目 + +## 实现分析 + +注意事项: 实现包含若干剪枝: + ++ 乘积上界剪枝 (若 m 大于元素乘积则跳过), 整数先验检查避免不必要的有理数搜索 ++ 有理数表示不做约分以减少开销但每次设置后均调用 `rat_fix_sign` 确保分母正 ++ 对于更大的 n 或更宽的元素范围需要额外优化 (如记忆化、子集 DP 或位掩码枚举) + +复杂度: 由于 n ≤ 4 且每个元素范围有限, 枚举非降序组合数量受限 (组合计数), 对于每个组合进行的递归搜索代价较高但在限制范围内可行. + +总体在最坏情况下为枚举组合数乘以每个组合的表达式枚举复杂度 (指数级但受 n ≤ 4 限制). + +- 实现要点: `main.cpp` 在多重集合层面生成所有非降序的长度为 n 的组合 (元素范围 [1,13]), 对每个组合先做快速的整数可达性搜索 (`dfs_int`), 如果存在纯整数表达式可以得到 m 则直接跳过 (因为题目要求所有表达式必须至少出现一次非整数中间结果). + +如果整数搜索不成立, 则进行有理数 (分数) 搜索 `dfs_rat` 判断是否存在任意表达式能达到 m (判断基于 a/b == m) + +整数搜索的除法仅在整除时允许; 有理数搜索在每次二元运算后用未约分的分子/分母表示并修正符号以避免分母为负. diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/main.cpp b/algorithm/2021F/lab_welcome/lab_welcome_G/main.cpp new file mode 100644 index 00000000..09121a8c --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/main.cpp @@ -0,0 +1,230 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ALGORITHM_TEST_MACRO +namespace lab_welcome_G{ +#endif + +using std::cin; +using std::tie; +using std::cout; +using std::list; +using std::sort; +using std::array; +using std::deque; +using std::queue; +using std::stack; +using std::tuple; +using std::string; +using std::vector; +using std::unordered_map; +using std::unordered_set; +using std::priority_queue; +static constexpr const char end{'\n'}; + +using num_t = int32_t; +using input_type = tuple; +using output_type = num_t; + +inline input_type read(); + +output_type cal(input_type data); + +void output(const output_type &data); + +int main() { + auto input_data = read(); + auto output_data = cal(input_data); + output(output_data); + return 0; +} + +inline input_type read() { + num_t a{0}, b{0}; + std::cin >> a >> b; + return std::make_tuple(a, b); +} + +// ------------- 快速存在性搜索(整数 / 有理数) ------------- +struct Rat { + int64_t a, b; // a/b, 仅保证 b > 0,不做约分 +}; + +static inline void rat_fix_sign(Rat &r) { + if (r.b < 0) { r.b = -r.b; r.a = -r.a; } +} + +// 纯整数搜索:除法仅在整除时允许 +static bool dfs_int(int64_t v[], int len, int64_t m) { + if (len == 1) return v[0] == m; + for (int i = 0; i < len; ++i) { + for (int j = i + 1; j < len; ++j) { + const int64_t x = v[i], y = v[j]; + const int64_t vi = v[i], vj = v[j], vlast = v[len - 1]; + + // 压缩:把最后一个移到 j 位置,用 i 放结果 + v[j] = vlast; + + // + + v[i] = x + y; + if (dfs_int(v, len - 1, m)) { v[i]=vi; v[j]=vj; v[len-1]=vlast; return true; } + // - + v[i] = x - y; + if (dfs_int(v, len - 1, m)) { v[i]=vi; v[j]=vj; v[len-1]=vlast; return true; } + v[i] = y - x; + if (dfs_int(v, len - 1, m)) { v[i]=vi; v[j]=vj; v[len-1]=vlast; return true; } + // * + v[i] = x * y; + if (dfs_int(v, len - 1, m)) { v[i]=vi; v[j]=vj; v[len-1]=vlast; return true; } + // / 整除 + if (y != 0 && x % y == 0) { + v[i] = x / y; + if (dfs_int(v, len - 1, m)) { v[i]=vi; v[j]=vj; v[len-1]=vlast; return true; } + } + if (x != 0 && y % x == 0) { + v[i] = y / x; + if (dfs_int(v, len - 1, m)) { v[i]=vi; v[j]=vj; v[len-1]=vlast; return true; } + } + + // 还原 + v[i] = vi; v[j] = vj; v[len - 1] = vlast; + } + } + return false; +} + +// 有理数搜索:a/b 表示,最终判断 a == m*b +static bool dfs_rat(Rat v[], int len, int64_t m) { + if (len == 1) { + // 判断是否等于整数 m(无需约分) + // 注意 b>0 已保证 + return v[0].a == m * v[0].b; + } + for (int i = 0; i < len; ++i) { + for (int j = i + 1; j < len; ++j) { + const Rat X = v[i], Y = v[j]; + const Rat Vi = v[i], Vj = v[j], Vlast = v[len - 1]; + + v[j] = Vlast; + + // + + v[i].a = X.a * Y.b + Y.a * X.b; + v[i].b = X.b * Y.b; rat_fix_sign(v[i]); + if (dfs_rat(v, len - 1, m)) { v[i]=Vi; v[j]=Vj; v[len-1]=Vlast; return true; } + + // - + v[i].a = X.a * Y.b - Y.a * X.b; + v[i].b = X.b * Y.b; rat_fix_sign(v[i]); + if (dfs_rat(v, len - 1, m)) { v[i]=Vi; v[j]=Vj; v[len-1]=Vlast; return true; } + + v[i].a = Y.a * X.b - X.a * Y.b; + v[i].b = X.b * Y.b; rat_fix_sign(v[i]); + if (dfs_rat(v, len - 1, m)) { v[i]=Vi; v[j]=Vj; v[len-1]=Vlast; return true; } + + // * + v[i].a = X.a * Y.a; + v[i].b = X.b * Y.b; rat_fix_sign(v[i]); + if (dfs_rat(v, len - 1, m)) { v[i]=Vi; v[j]=Vj; v[len-1]=Vlast; return true; } + + // / + if (Y.a != 0) { + v[i].a = X.a * Y.b; + v[i].b = X.b * Y.a; rat_fix_sign(v[i]); + if (dfs_rat(v, len - 1, m)) { v[i]=Vi; v[j]=Vj; v[len-1]=Vlast; return true; } + } + if (X.a != 0) { + v[i].a = Y.a * X.b; + v[i].b = Y.b * X.a; rat_fix_sign(v[i]); + if (dfs_rat(v, len - 1, m)) { v[i]=Vi; v[j]=Vj; v[len-1]=Vlast; return true; } + } + + v[i] = Vi; v[j] = Vj; v[len - 1] = Vlast; + } + } + return false; +} + +// 生成非降序多重集并统计 +static void gen_multisets_and_count(int n, int64_t m, output_type &ans) { + vector cur(n, 1); + + // 递归生成 + struct Local { + static void go(int idx, int last, int n, int64_t m, vector& cur, output_type& ans) { + if (idx == n) { + // 乘积上界裁剪 + int64_t prod = 1; + for (int i = 0; i < n; ++i) prod *= cur[i]; + if (m > prod) return; + + // 先整数存在性 + int64_t iv[4]; + for (int i = 0; i < n; ++i) iv[i] = cur[i]; + if (dfs_int(iv, n, m)) return; // 存在纯整数表达式 => 不合法 + + // 再有理数存在性 + Rat rv[4]; + for (int i = 0; i < n; ++i) { rv[i].a = cur[i]; rv[i].b = 1; } + if (dfs_rat(rv, n, m)) ++ans; + return; + } + for (int v = last; v <= 13; ++v) { + cur[idx] = v; + go(idx + 1, v, n, m, cur, ans); + } + } + }; + Local::go(0, 1, n, m, cur, ans); +} + +output_type cal(input_type data) { + num_t n{0}; + int64_t m{0}; + tie(n, m) = data; + + // 全局上界:若 m > 13^n,直接为 0 + int64_t global_max = 1; + for (int i = 0; i < n; ++i) global_max *= 13; + if (m > global_max) return 0; + + output_type ans = 0; + gen_multisets_and_count(n, m, ans); + return ans; +} + +void output(const output_type &data) { + cout << data << end; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + // use time to init the random seed + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + // 关闭c++风格输入输出 , 与C风格输入输出的同步, 提高性能. + return 0; +}(); + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/main_old.cpp b/algorithm/2021F/lab_welcome/lab_welcome_G/main_old.cpp new file mode 100644 index 00000000..1cc2f1ea --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/main_old.cpp @@ -0,0 +1,331 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef ALGORITHM_TEST_MACRO +namespace lab_welcome_G{ +#endif + +using std::cin; +using std::tie; +using std::cout; +using std::list; +using std::sort; +using std::array; +using std::deque; +using std::queue; +using std::stack; +using std::tuple; +using std::string; +using std::vector; +using std::unordered_map; +using std::unordered_set; +using std::priority_queue; +static constexpr const char end{'\n'}; + +using num_t = int32_t; +using input_type = tuple; +using output_type = num_t; + +inline input_type read(); + +output_type cal(input_type data); + +void output(const output_type &data); + +// gcd for older compilers +static inline int64_t igcd(int64_t a, int64_t b) { + if (a < 0) a = -a; + if (b < 0) b = -b; + while (b) { + int64_t t = a % b; + a = b; + b = t; + } + return a; +} + +static inline uint64_t splitmix64(uint64_t x) { + x += 0x9e3779b97f4a7c15ULL; + x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL; + x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL; + return x ^ (x >> 31); +} + +struct Frac { + int64_t p, q; // q > 0, reduced; 0 -> 0/1 + Frac() : p(0), q(1) {} + Frac(int64_t _p, int64_t _q) : p(_p), q(_q) { norm(); } + inline void norm() { + if (q < 0) { q = -q; p = -p; } + if (p == 0) { q = 1; return; } + int64_t a = p >= 0 ? p : -p; + int64_t b = q >= 0 ? q : -q; + int64_t g = igcd(a, b); + if (g > 1) { p /= g; q /= g; } + } +}; + +static inline Frac add(const Frac& a, const Frac& b) { + return Frac(a.p * b.q + b.p * a.q, a.q * b.q); +} +static inline Frac sub(const Frac& a, const Frac& b) { + return Frac(a.p * b.q - b.p * a.q, a.q * b.q); +} +static inline Frac mul(const Frac& a, const Frac& b) { + return Frac(a.p * b.p, a.q * b.q); +} +static inline bool is_zero(const Frac& a) { return a.p == 0; } +static inline Frac divide(const Frac& a, const Frac& b) { + return Frac(a.p * b.q, a.q * b.p); +} + +static inline uint64_t hash_int_vec(const vector& v) { + uint64_t h = 1469598103934665603ULL; + h ^= splitmix64((uint64_t)v.size() + 0x9e3779b97f4a7c15ULL); + for (auto x : v) { + uint64_t y = (uint64_t)x ^ (uint64_t)(x << 23) ^ (uint64_t)(x >> 17); + h ^= splitmix64(y + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2)); + } + return h; +} +static inline uint64_t hash_frac_vec(vector v) { + sort(v.begin(), v.end(), [](const Frac& a, const Frac& b){ + if (a.p != b.p) return a.p < b.p; + return a.q < b.q; + }); + uint64_t h = 1099511628211ULL; + h ^= splitmix64((uint64_t)v.size() + 0x517cc1b727220a95ULL); + for (auto &f : v) { + uint64_t a = splitmix64((uint64_t)f.p ^ 0x9e3779b97f4a7c15ULL); + uint64_t b = splitmix64((uint64_t)f.q ^ 0x94d049bb133111ebULL); + h ^= splitmix64(a + 0x9e3779b97f4a7c15ULL + (h << 6) + (h >> 2)); + h ^= splitmix64(b + 0xbf58476d1ce4e5b9ULL + (h << 7) + (h >> 1)); + } + return h; +} + +static inline void canonical_sort(vector& v) { + sort(v.begin(), v.end()); +} +static inline void canonical_sort(vector& v) { + sort(v.begin(), v.end(), [](const Frac& a, const Frac& b){ + if (a.p != b.p) return a.p < b.p; + return a.q < b.q; + }); +} + +static bool canReachIntTarget(const vector& nums_in, int64_t target, + unordered_set& memo) { + vector nums = nums_in; + canonical_sort(nums); + const size_t n = nums.size(); + uint64_t key = hash_int_vec(nums); + if (memo.find(key) != memo.end()) return false; + if (n == 1) { + return nums[0] == target; + } + for (size_t i = 0; i < n; ++i) { + for (size_t j = i + 1; j < n; ++j) { + int64_t a = nums[i], b = nums[j]; + vector rest; + rest.reserve(n - 1); + for (size_t k = 0; k < n; ++k) { + if (k != i && k != j) rest.push_back(nums[k]); + } + // a + b + { + vector nxt = rest; + nxt.push_back(a + b); + if (canReachIntTarget(nxt, target, memo)) return true; + } + // a - b + { + vector nxt = rest; + nxt.push_back(a - b); + if (canReachIntTarget(nxt, target, memo)) return true; + } + // b - a + { + vector nxt = rest; + nxt.push_back(b - a); + if (canReachIntTarget(nxt, target, memo)) return true; + } + // a * b + { + vector nxt = rest; + nxt.push_back(a * b); + if (canReachIntTarget(nxt, target, memo)) return true; + } + // divisions (exact only) + if (b != 0 && (a % b == 0)) { + vector nxt = rest; + nxt.push_back(a / b); + if (canReachIntTarget(nxt, target, memo)) return true; + } + if (a != 0 && (b % a == 0)) { + vector nxt = rest; + nxt.push_back(b / a); + if (canReachIntTarget(nxt, target, memo)) return true; + } + } + } + memo.insert(key); + return false; +} + +static bool canReachRationalTarget(const vector& nums_in, int64_t target, + unordered_set& memo) { + vector nums = nums_in; + canonical_sort(nums); + const size_t n = nums.size(); + uint64_t key = hash_frac_vec(nums); + if (memo.find(key) != memo.end()) return false; + if (n == 1) { + return nums[0].p == target * nums[0].q; + } + for (size_t i = 0; i < n; ++i) { + for (size_t j = i + 1; j < n; ++j) { + Frac a = nums[i], b = nums[j]; + vector rest; + rest.reserve(n - 1); + for (size_t k = 0; k < n; ++k) { + if (k != i && k != j) rest.push_back(nums[k]); + } + // a + b + { + vector nxt = rest; + nxt.push_back(add(a, b)); + if (canReachRationalTarget(nxt, target, memo)) return true; + } + // a - b + { + vector nxt = rest; + nxt.push_back(sub(a, b)); + if (canReachRationalTarget(nxt, target, memo)) return true; + } + // b - a + { + vector nxt = rest; + nxt.push_back(sub(b, a)); + if (canReachRationalTarget(nxt, target, memo)) return true; + } + // a * b + { + vector nxt = rest; + nxt.push_back(mul(a, b)); + if (canReachRationalTarget(nxt, target, memo)) return true; + } + // a / b + if (!is_zero(b)) { + vector nxt = rest; + nxt.push_back(divide(a, b)); + if (canReachRationalTarget(nxt, target, memo)) return true; + } + // b / a + if (!is_zero(a)) { + vector nxt = rest; + nxt.push_back(divide(b, a)); + if (canReachRationalTarget(nxt, target, memo)) return true; + } + } + } + memo.insert(key); + return false; +} + +static void dfs_gen(int n, int idx, int last, vector& cur, int64_t m, int32_t& answer) { + if (idx == n) { + vector ints; + ints.reserve(n); + for (int i = 0; i < n; ++i) ints.push_back(cur[i]); + + unordered_set memoInt; + memoInt.reserve(1024); + if (canReachIntTarget(ints, m, memoInt)) { + return; // invalid: has an all-integer path to m + } + + vector frs; + frs.reserve(n); + for (int i = 0; i < n; ++i) frs.emplace_back((int64_t)cur[i], 1); + unordered_set memoRat; + memoRat.reserve(2048); + if (canReachRationalTarget(frs, m, memoRat)) { + ++answer; // valid: can reach m, but integer-only cannot + } + return; + } + for (int v = last; v <= 13; ++v) { + cur[idx] = v; + dfs_gen(n, idx + 1, v, cur, m, answer); + } +} + +output_type cal(input_type data) { + num_t n{0}; + int64_t m{0}; + tie(n, m) = data; + + // Quick short-circuit filters to avoid expensive enumeration: + // 1) If n < 3, the condition "every expression has at least one non-integer intermediate" + // cannot be satisfied (too few operations), so answer is 0. + if (n < 3) return 0; + // 2) If |m| > 13^n, impossible to reach m with numbers in [1,13]. Compute 13^n safely. + int64_t maxv = 1; + for (int i = 0; i < n; ++i) maxv *= 13; + if (m < 0 ? -m : m > maxv) return 0; + + int32_t answer = 0; + if (n >= 1 && n <= 4) { + vector cur(n, 1); + dfs_gen(n, 0, 1, cur, m, answer); + } + + return answer; +} + +void output(const output_type &data) { + cout << data << end; +} + +static const auto faster_streams = [] { + srand(time(nullptr)); + std::ios::sync_with_stdio(false); + std::istream::sync_with_stdio(false); + std::ostream::sync_with_stdio(false); + std::cin.tie(nullptr); + std::cout.tie(nullptr); + return 0; +}(); + +int main() { + auto input_data = read(); + auto output_data = cal(input_data); + output(output_data); + return 0; +} + +inline input_type read() { + num_t a{0}, b{0}; + std::cin >> a >> b; + return std::make_tuple(a, b); +} + +#ifdef ALGORITHM_TEST_MACRO +} +#endif diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/01.data.in b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/01.data.in new file mode 100644 index 00000000..9649e564 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/01.data.in @@ -0,0 +1 @@ +4 159 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/01.data.out b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/01.data.out new file mode 100644 index 00000000..45a4fb75 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/01.data.out @@ -0,0 +1 @@ +8 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/02.data.in b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/02.data.in new file mode 100644 index 00000000..0d6a524b --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/02.data.in @@ -0,0 +1 @@ +1 5 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/02.data.out b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/02.data.out new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/02.data.out @@ -0,0 +1 @@ +0 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/03.data.in b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/03.data.in new file mode 100644 index 00000000..4eca198a --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/03.data.in @@ -0,0 +1 @@ +2 24 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/03.data.out b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/03.data.out new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/03.data.out @@ -0,0 +1 @@ +0 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/04.data.in b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/04.data.in new file mode 100644 index 00000000..6f2c3444 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/04.data.in @@ -0,0 +1 @@ +3 24 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/04.data.out b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/04.data.out new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/04.data.out @@ -0,0 +1 @@ +0 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/05.data.in b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/05.data.in new file mode 100644 index 00000000..7f0887ae --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/05.data.in @@ -0,0 +1 @@ +4 24 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/05.data.out b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/05.data.out new file mode 100644 index 00000000..b6a7d89c --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/05.data.out @@ -0,0 +1 @@ +16 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/06.data.in b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/06.data.in new file mode 100644 index 00000000..9649e564 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/06.data.in @@ -0,0 +1 @@ +4 159 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/06.data.out b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/06.data.out new file mode 100644 index 00000000..45a4fb75 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/06.data.out @@ -0,0 +1 @@ +8 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/07.data.in b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/07.data.in new file mode 100644 index 00000000..304e6384 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/07.data.in @@ -0,0 +1 @@ +4 1000 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/07.data.out b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/07.data.out new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/07.data.out @@ -0,0 +1 @@ +0 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/08.data.in b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/08.data.in new file mode 100644 index 00000000..0871b0b4 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/08.data.in @@ -0,0 +1 @@ +3 7 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/08.data.out b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/08.data.out new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/08.data.out @@ -0,0 +1 @@ +0 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/09.data.in b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/09.data.in new file mode 100644 index 00000000..d260f56e --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/09.data.in @@ -0,0 +1 @@ +2 202 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/09.data.out b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/09.data.out new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/09.data.out @@ -0,0 +1 @@ +0 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/10.data.in b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/10.data.in new file mode 100644 index 00000000..632fec90 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/10.data.in @@ -0,0 +1 @@ +4 500 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/10.data.out b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/10.data.out new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/10.data.out @@ -0,0 +1 @@ +0 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/11.data.in b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/11.data.in new file mode 100644 index 00000000..5c06f27c --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/11.data.in @@ -0,0 +1 @@ +4 100000000 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/resource/11.data.out b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/11.data.out new file mode 100644 index 00000000..573541ac --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/resource/11.data.out @@ -0,0 +1 @@ +0 diff --git a/algorithm/2021F/lab_welcome/lab_welcome_G/test.cpp b/algorithm/2021F/lab_welcome/lab_welcome_G/test.cpp new file mode 100644 index 00000000..39e70dc8 --- /dev/null +++ b/algorithm/2021F/lab_welcome/lab_welcome_G/test.cpp @@ -0,0 +1,49 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-FileCopyrightText: 2020-2025 nanoseeds +#ifdef ALGORITHM_TEST_MACRO + +#include +#include +#include +#include +#include + +#include "main.cpp" + +std::string getFilePath() noexcept { return "./../../../../../algorithm/2021F/lab_welcome/lab_welcome_G/resource/"; } + +const std::string CS203_redirect::file_paths = getFilePath(); + +namespace lab_welcome_G { + +using std::tie; +using std::cin; +using std::cout; +using std::tuple; +using std::vector; + +using Catch::Matchers::Equals; +using Catch::Matchers::UnorderedEquals; +using Catch::Matchers::Contains; + +TEST_CASE("test case with sequence", "[test welcome G]") { + CS203_sequence sequence{1, 2, 2}; // // 基础设定,[1,11] + sequence.set_postfix_of_datain("data.in"); // 输入数据后缀,默认为 data.in + sequence.set_postfix_of_dataout("data.out"); // except输出数据后缀,默认为 data.out + sequence.set_postfix_of_testout("test.out"); // 测试输出数据后缀,默认为 test.out + const auto files_name = sequence.get_files(true); + // 获取一个std::tuple , + // 其中每个tuple内为 `输入数据`,`except输出数据`,`测试输出数据`名. + for (const auto &file_name: files_name) { + string datain, dataout, testout; // 声明 + tie(datain, dataout, testout) = file_name; // 解包 + { + const CS203_redirect cr{datain, testout}; // 重定向输入,输出 + main(); + // 用括号括住是为了让CS203_redirect在这里被析构,停止重定向 + } + CHECK(compareFiles(testout, dataout)); + } +} +} +#endif //ALGORITHM_TEST_MACRO diff --git a/include/include/CS203_sequence.hpp b/include/include/CS203_sequence.hpp index 2c8937d5..e6cf6879 100644 --- a/include/include/CS203_sequence.hpp +++ b/include/include/CS203_sequence.hpp @@ -31,7 +31,7 @@ class CS203_sequence final : private nonCopyMoveAble { public: // default path1 is input and path2 is output - explicit CS203_sequence(int32_t begin, int32_t end, int32_t max_length = -1) : begin(begin), end(end), + explicit CS203_sequence(const int32_t begin, const int32_t end, const int32_t max_length = 2) : begin(begin), end(end), max_length(max_length) {} void set_prefix_of_filename(const string &prefixOfFileName) { @@ -93,7 +93,7 @@ class CS203_sequence final : private nonCopyMoveAble { const string datain = prefix_of_file_name + item + "." + postfix_of_datain; const string dataout = prefix_of_file_name + item + "." + postfix_of_dataout; const string testout = prefix_of_file_name + item + "." + postfix_of_testout; - will_return.push_back(std::make_tuple(datain, dataout, testout)); + will_return.emplace_back(datain, dataout, testout); } return will_return; } diff --git a/lab_00/CMakeLists.txt b/lab_00/CMakeLists.txt index 48e7ae84..04b1ee87 100644 --- a/lab_00/CMakeLists.txt +++ b/lab_00/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16.6) set(PROJECT_ORDER lab_00) -project(CS203_${PROJECT_ORDER}) +project(ALGORITHM_${PROJECT_ORDER}) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") diff --git a/lab_00/lab_00_A/CMakeLists.txt b/lab_00/lab_00_A/CMakeLists.txt index 354751e1..40897f09 100644 --- a/lab_00/lab_00_A/CMakeLists.txt +++ b/lab_00/lab_00_A/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/lab_00/lab_00_A/lab_00_A.cpp b/lab_00/lab_00_A/main.cpp similarity index 100% rename from lab_00/lab_00_A/lab_00_A.cpp rename to lab_00/lab_00_A/main.cpp diff --git a/lab_00/lab_00_A/lab_00_A_test.cpp b/lab_00/lab_00_A/test.cpp similarity index 98% rename from lab_00/lab_00_A/lab_00_A_test.cpp rename to lab_00/lab_00_A/test.cpp index 0ea0e60b..d809b2e7 100644 --- a/lab_00/lab_00_A/lab_00_A_test.cpp +++ b/lab_00/lab_00_A/test.cpp @@ -8,7 +8,7 @@ #include #include -#include "lab_00_A.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../lab_00/lab_00_A/resource/"; } diff --git a/lab_00/lab_00_B/CMakeLists.txt b/lab_00/lab_00_B/CMakeLists.txt index c490830a..dac0839a 100644 --- a/lab_00/lab_00_B/CMakeLists.txt +++ b/lab_00/lab_00_B/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/lab_00/lab_00_B/lab_00_B.cpp b/lab_00/lab_00_B/main.cpp similarity index 100% rename from lab_00/lab_00_B/lab_00_B.cpp rename to lab_00/lab_00_B/main.cpp diff --git a/lab_00/lab_00_B/lab_00_B_test.cpp b/lab_00/lab_00_B/test.cpp similarity index 98% rename from lab_00/lab_00_B/lab_00_B_test.cpp rename to lab_00/lab_00_B/test.cpp index 8507e954..d5d7ec22 100644 --- a/lab_00/lab_00_B/lab_00_B_test.cpp +++ b/lab_00/lab_00_B/test.cpp @@ -7,7 +7,7 @@ #include #include #include -#include "lab_00_B.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../lab_00/lab_00_B/resource/"; } diff --git a/lab_00/lab_00_C/CMakeLists.txt b/lab_00/lab_00_C/CMakeLists.txt index e14261f1..62fbe7d9 100644 --- a/lab_00/lab_00_C/CMakeLists.txt +++ b/lab_00/lab_00_C/CMakeLists.txt @@ -6,12 +6,12 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) unset(PROBLEM_ORDER) diff --git a/lab_00/lab_00_C/lab_00_C.cpp b/lab_00/lab_00_C/main.cpp similarity index 100% rename from lab_00/lab_00_C/lab_00_C.cpp rename to lab_00/lab_00_C/main.cpp diff --git a/lab_00/lab_00_C/lab_00_C_test.cpp b/lab_00/lab_00_C/test.cpp similarity index 99% rename from lab_00/lab_00_C/lab_00_C_test.cpp rename to lab_00/lab_00_C/test.cpp index a6eed29c..8df59b74 100644 --- a/lab_00/lab_00_C/lab_00_C_test.cpp +++ b/lab_00/lab_00_C/test.cpp @@ -5,7 +5,7 @@ #include #include #include -#include "lab_00_C.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../lab_00/lab_00_C/resource/"; } diff --git a/lab_00/lab_00_D/CMakeLists.txt b/lab_00/lab_00_D/CMakeLists.txt index dce330ce..564aeae5 100644 --- a/lab_00/lab_00_D/CMakeLists.txt +++ b/lab_00/lab_00_D/CMakeLists.txt @@ -6,11 +6,11 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") enable_testing() -add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}.cpp) +add_executable(${PROJECT_NAME} ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp) +add_executable(${PROJECT_NAME}_test ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp) target_compile_definitions(${PROJECT_NAME}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${PROJECT_NAME}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_ORDER}_${PROBLEM_ORDER}_test.cpp") +MESSAGE(STATUS "${PROJECT_NAME}_${elementName} from ${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") add_test(${PROJECT_NAME}_CTEST ${PROJECT_NAME}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/lab_00/lab_00_D/lab_00_D.cpp b/lab_00/lab_00_D/main.cpp similarity index 100% rename from lab_00/lab_00_D/lab_00_D.cpp rename to lab_00/lab_00_D/main.cpp diff --git a/lab_00/lab_00_D/lab_00_D_test.cpp b/lab_00/lab_00_D/test.cpp similarity index 97% rename from lab_00/lab_00_D/lab_00_D_test.cpp rename to lab_00/lab_00_D/test.cpp index 9367b2ee..ae4043b6 100644 --- a/lab_00/lab_00_D/lab_00_D_test.cpp +++ b/lab_00/lab_00_D/test.cpp @@ -5,7 +5,7 @@ #include #include #include -#include "lab_00_D.cpp" +#include "main.cpp" std::string getFilePath() noexcept { return "./../../../lab_00/lab_00_D/resource/"; } diff --git a/script/cmake_level1_template.txt b/script/cmake_level1_template.txt index 838cb332..e9dd5fd0 100644 --- a/script/cmake_level1_template.txt +++ b/script/cmake_level1_template.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16.6) set(PROJECT_ORDER lab_{0}) -project(CS203_${{PROJECT_ORDER}}) +project(ALGORITHM_${{PROJECT_ORDER}}) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${{CMAKE_CXX_FLAGS}}") diff --git a/script/cmake_level2_template.txt b/script/cmake_level2_template.txt index 5a125db7..0482182b 100644 --- a/script/cmake_level2_template.txt +++ b/script/cmake_level2_template.txt @@ -6,12 +6,12 @@ set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_FLAGS "${{CMAKE_CXX_FLAGS}}") enable_testing() -add_executable(${{PROJECT_NAME}} ${{CMAKE_CURRENT_SOURCE_DIR}}/${{PROJECT_ORDER}}_${{PROBLEM_ORDER}}.cpp) +add_executable(${{PROJECT_NAME}} ${{CMAKE_CURRENT_SOURCE_DIR}}/main.cpp) set(CMAKE_CXX_STANDARD 17) -add_executable(${{PROJECT_NAME}}_test ${{CMAKE_CURRENT_SOURCE_DIR}}/${{PROJECT_ORDER}}_${{PROBLEM_ORDER}}_test.cpp) +add_executable(${{PROJECT_NAME}}_test ${{CMAKE_CURRENT_SOURCE_DIR}}/test.cpp) target_compile_definitions(${{PROJECT_NAME}}_test PRIVATE ALGORITHM_TEST_MACRO) target_link_libraries(${{PROJECT_NAME}}_test PRIVATE algorithm_template_INCLUDE) -MESSAGE(STATUS "${{PROJECT_NAME}} from ${{CMAKE_CURRENT_SOURCE_DIR}}/${{PROJECT_ORDER}}_${{PROBLEM_ORDER}}.cpp") +MESSAGE(STATUS "${{PROJECT_NAME}} from ${{CMAKE_CURRENT_SOURCE_DIR}}/test.cpp") add_test(${{PROJECT_NAME}}_CTEST ${{PROJECT_NAME}}_test) set(CMAKE_CXX_STANDARD 11) diff --git a/script/cpp_template.txt b/script/cpp_template.txt index cd8e0c2a..4ca983be 100644 --- a/script/cpp_template.txt +++ b/script/cpp_template.txt @@ -14,7 +14,12 @@ #include #include -#ifdef ALGORITHM_TEST_MACRO +#ifndef ALGORITHM_TEST_MACRO +#pragma GCC optimize(3, "Ofast", "inline", "no-stack-protector", "unroll-loops") +#pragma GCC optimize("inline-small-functions") +#pragma GCC optimize("-finline-small-functions") +#pragma GCC target("tune=native") +#else namespace lab_{0}_{1}{{ #endif diff --git a/script/cpp_test_template.txt b/script/cpp_test_template.txt index a565c4ed..badaff4f 100644 --- a/script/cpp_test_template.txt +++ b/script/cpp_test_template.txt @@ -7,7 +7,7 @@ #include #include -#include "lab_{0}_{1}.cpp" +#include "main.cpp" std::string getFilePath() noexcept {{ return "./../../../lab_{0}/lab_{0}_{1}/resource/"; }} const std::string CS203_redirect::file_paths = getFilePath(); diff --git a/script/file_header.txt b/script/file_header.txt index 7d4bdab4..eeef3331 100644 --- a/script/file_header.txt +++ b/script/file_header.txt @@ -1,2 +1,2 @@ -// SPDX-License-Identifier: AGPL-3.0-or-later +// SPDX-License-Identifier: Apache-2.0 // SPDX-FileCopyrightText: 2020-{0} {1} diff --git a/script/file_template.py b/script/file_template.py index ed463dbb..f800014c 100644 --- a/script/file_template.py +++ b/script/file_template.py @@ -17,7 +17,7 @@ level1_cmake_template: str level2_cmake_template: str test_cmake_template: str -USER: str = 'nanoseeds' # replace it with your user name # example: nanoseeds +USER: str = 'USER' # replace it with your user name # example: nanoseeds year: str = time.strftime('%Y', time.localtime()) main_cmake_path: str = './../CMakeLists.txt' @@ -30,12 +30,12 @@ def read_file(file_name: str) -> str: def fill_file(lab_number: str, problem_order: str) -> None: - with open(f'./../lab_{lab_number}/lab_{lab_number}_{problem_order}/lab_{lab_number}_{problem_order}.cpp', mode='a+', + with open(f'./../lab_{lab_number}/lab_{lab_number}_{problem_order}/main.cpp', mode='a+', encoding='UTF-8') as file: file.write(file_header_template.format(year, USER)) file.write(main_code_template.format(lab_number, problem_order)) print('main finish') - with open(f'./../lab_{lab_number}/lab_{lab_number}_{problem_order}/lab_{lab_number}_{problem_order}_test.cpp', + with open(f'./../lab_{lab_number}/lab_{lab_number}_{problem_order}/test.cpp', mode='a+', encoding='UTF-8') as file: file.write(file_header_template.format(year, USER)) file.write(test_code_template.format(lab_number, problem_order)) @@ -65,9 +65,9 @@ def main() -> None: labs: List[str] = ['welcome', '02', '03', '04', '05', '06', '07', '08', '09', '10', 'bonus'] problem_order: List[str] = ['A', 'B', 'C', 'D', 'E', 'F'] - labs: List[str] = ['01'] # problem_order: List[str] = ['A', 'B', 'C', # 'D', 'E', 'F', 'G', 'H', 'I', 'J'] + labs: List[str] = ['01'] for i in labs: try_mkdir(i, problem_order) copy_cmakeLists(i, problem_order) # prepare CMakeLists