Harbour.Space Scholarship Contest 2023-2024 (Div. 1 + Div. 2)
A. 给三个数
, 。 严格递增。- 定义
, 严格递减。
显然前两个条件非常宽松,定义好起始点,让
显然
view
#include <bits/stdc++.h> typedef long long ll; void solve() { int x, y, n; std::cin >> x >> y >> n; std::vector<int> a(n+1); a[1] = x; a[n] = y; for (int i = n - 1, cur = 1; i >= 2; --i, cur++) { a[i] = a[i + 1] - cur; } if (a[2] - a[1] >= n - 1) for (int i = 1; i <= n; i++) std::cout << a[i] << " \n"[i==n]; else std::cout << -1 << '\n'; } int main() { int _ = 1; std::cin >> _; while ( _-- ) { solve(); } return 0; }
B. 给一个长为
- 交换第
位和第 位字符 第 位到 位的字符
经过任意次上次操作后使
- 允许无限次交换次数的情况下:第一步操作意味着可以任意排列偶数位和奇数位上的字符。
- 允许无限次
的情况下: 即 段的长度为奇数时时不会改变奇偶位。答案唯一。 即 段的长度为偶数时 ,即整段 ,互换所有的奇偶位,此时答案为两种选一。(虽然这题没这个条件,没意思) ,可以互换任意一对奇数位元素和偶数位元素。
故讨论
view
#include <bits/stdc++.h> typedef long long ll; char s[2000005], s_odd[2000005], s_even[2000005]; void solve() { int n, k; std::cin >> n >> k; for (int i = 1; i <= n; i++) { std::cin >> s[i]; if (i & 1) s_odd[(i+1)/2] = s[i]; else s_even[i/2] = s[i]; } std::string ans = ""; if (k & 1) { std::sort(s_odd + 1, s_odd + (n+1)/2 + 1, [&](char a, char b){ return a < b; }); std::sort(s_even + 1, s_even + n/2 + 1, [&](char a, char b){ return a < b; }); for (int i = 1; i <= n/2; i++) ans += s_odd[i], ans += s_even[i]; if (n&1) ans += s_odd[n/2+1]; } else { if (k == n) { std::string ts1 = "", ts2 = ""; std::sort(s_odd + 1, s_odd + (n+1)/2 + 1, [&](char a, char b){ return a < b; }); std::sort(s_even + 1, s_even + n/2 + 1, [&](char a, char b){ return a < b; }); for (int i = 1; i <= n/2; i++) ts1 += s_odd[i], ts1 += s_even[i]; if (n&1) ans += s_odd[n/2+1]; for (int i = n; i; --i) { int l = n - i + 1; if (l & 1) s_odd[(l+1)/2] = s[i]; else s_even[l/2] = s[i]; } std::sort(s_odd + 1, s_odd + (n+1)/2 + 1, [&](char a, char b){ return a < b; }); std::sort(s_even + 1, s_even + n/2 + 1, [&](char a, char b){ return a < b; }); for (int i = 1; i <= n/2; i++) ts2 += s_odd[i], ts2 += s_even[i]; if (n&1) ans += s_odd[n/2+1]; ans = std::min(ts1, ts2); } if (k < n) { std::sort(s + 1, s + n + 1, [&](char a, char b){ return a < b; }); for (int i = 1; i <= n; i++) ans += s[i]; } } std::cout << ans << '\n'; } int main() { int _ = 1; std::cin >> _; while ( _-- ) { solve(); } return 0; }
C. 给一个数
题目其实有引导性地让我们分两步做,每一步每个因子至多会用到一次。
方法:以二进制形式观察
- 第一步,让
每次减去最低位的 直到 只余一个 。 - 第二部,让
的 每次右移一位直到变为 。
第一步,显然二进制上任意一个
只需证:
证明:将二进制低位到高位编号,最低位为
第二步,也显然余下的
两步分别用到的因子不重复,故总的用到的因子不会重复
view
#include <bits/stdc++.h> typedef long long ll; void solve() { int x; std::cin >> x; std::vector<int> ans(1, x); while ( __builtin_popcount(x) != 1 ) { x -= ( x & ( -x ) ); ans.push_back(x); } while (x != 1) { x >>= 1; ans.push_back(x); } int m = ans.size(); std::cout << m << '\n'; for (int i = 0; i < m; i++) std::cout << ans[i] << " \n"[i==m-1]; } int main() { int _ = 1; std::cin >> _; while ( _-- ) { solve(); } return 0; }
D. 给一个
对
- 自身翻转,即
。 - 任意
位置满足 的格子翻转,满足 的格子翻转。
解方程:
不要被笛卡尔坐标系给荼毒了……。
在所给坐标系中是垂直向下九十度的扇形。
考虑:
翻转最 的性质:一个位置翻转 次,只有其中的 次是有意义的。- 网格内操作某个格子带动翻转一个区域且“翻转形式唯一或能转化为翻转形式唯一”的情形,具备一些性质:(只有区域翻转形式唯一情况下才能直接进行数理讨论,否则考虑
等方案)- 任何方向有后效性的翻转:当边界行(通常选第一行)的状态确定,整个方格的状态唯一确定。可以知晓有无解,有解时的最小操作次数。
- 证明:当边界行状态确定,由于后效性存在,不存在一种方案可以维持已确定的边界行的状态且改变其他行。
- 推论:当边界格的状态唯一确定,整行的状态唯一确定。
- 存在或可转化为一个方向无后效性的翻转:贪心地选择无后效性的方向翻转一定有解,当方向唯一时最小操作次数唯一。(比如此题的格子翻转严格影响向下的区域)
- 证明:有解性显然。最优性可以反证按其他方向翻转不会更优。
- 任何方向有后效性的翻转:当边界行(通常选第一行)的状态确定,整个方格的状态唯一确定。可以知晓有无解,有解时的最小操作次数。
于是此题变为,如何在
- 仅按从上到下的方向操作所有
便是 的,所以操作复杂度需要是 或 。 - 于是面临两个问题:
- 空间允许情况下容易想到二维区间修改,很像需同时修改和询问。
- 差分空间非水平,而是斜率为
和 的空间。
这调用 将会是一套繁杂的推式子和代码实现。
- 向下斜率为正负
的区间修改问题,是经典的三角形压标记问题。(也可理解为 )(jls 和 dls 都是这种方法写的)- 我们只需要在
意义即位异或意义下,下放 合并更新即可。 - 把标记压到左右后驱。若左右后驱都存在,则给中后驱的中后驱放一个负标记(如果它存在)。更新信息时不仅要加上自己的标记,还要加上中前驱的标记。
(待补图) - 推广:二维上的任意三角形区间修改与询问,都可以使用这种总时间复杂度为
的方法,与询问一起离线解决。即根据扫描线顺序排序,然后下压。若区间询问,再借助一个数据结构如树状数组即可。
- 我们只需要在
时间复杂度
view
#include <bits/stdc++.h> typedef long long ll; void solve() { int n; std::cin >> n; std::vector<std::vector<int> > a(n+1, std::vector<int>(n+1)), tag(n+1, std::vector<int>(n+1)); for (int i = 1; i <= n; i++) { std::string s; std::cin >> s; for (int j = 1; j <= n; j++) { a[i][j] = (s[j - 1] - '0'); } } auto settag = [&](int i, int j, int t) { tag[i][j] = ( tag[i][j] + t + 2 ) % 2; a[i][j] = ( a[i][j] + t + 2 ) % 2; }; auto pushdown = [&](int i, int j) { if (i + 1 <= n) { a[i + 1][j] = ( a[i + 1][j] + tag[i][j] ) % 2; if (j - 1 >= 1) settag( i + 1 , j - 1 , tag[i][j] ); if (j + 1 <= n) settag( i + 1 , j + 1 , tag[i][j] ); } if (i + 2 <= n && j - 1 >= 1 && j + 1 <= n) { settag( i + 2 , j , -tag[i][j] ); } tag[i][j] = 0; }; int ans = 0; for (int i = 1; i <= n; i++) { for (int j = 1; j <= n; j++) { if (a[i][j]) ans++, settag(i, j, 1); pushdown(i, j); } } std::cout << ans << '\n'; } int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); int _ = 1; std::cin >> _; while ( _-- ) { solve(); } return 0; }
E.
——永远是挑战而不是练习,下次一定更好。
分类:
cf
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效