2025年天梯题解(L1-8 + L2)

打印 上一主题 下一主题

主题 1920|帖子 1920|积分 5764

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
L1-112 当代战争

题目
既然是从大到小轰炸,将全部点存储为三元组(value, x, y)。
排序之后, 记载行列被轰炸的编号,进行 k 次挑选即可。
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. constexpr int MAXN = 1000;
  4. struct Node { int val, r, c; };
  5. static Node v[MAXN*MAXN + 5];
  6. static int  mat[MAXN+5][MAXN+5];
  7. static bool row_boom[MAXN+5], col_boom[MAXN+5];
  8. int main(){
  9.     ios::sync_with_stdio(false);
  10.     cin.tie(nullptr);
  11.     int n, m, k;
  12.     cin >> n >> m >> k;
  13.     // 1) 读入矩阵,扁平化到 v[]
  14.     int tot = 0;
  15.     for(int i = 1; i <= n; i++){
  16.         for(int j = 1; j <= m; j++){
  17.             cin >> mat[i][j];
  18.             v[tot++] = { mat[i][j], i, j };
  19.         }
  20.     }
  21.     // 2) 按值从大到小排序
  22.     sort(v, v + tot, [](auto &A, auto &B){
  23.         return A.val > B.val;
  24.     });
  25.     // 3) 选 k 个“炸弹”行列
  26.     int cnt = 0;
  27.     for(int i = 0; i < tot && cnt < k; i++){
  28.         int rr = v[i].r, cc = v[i].c;
  29.         if(!row_boom[rr] && !col_boom[cc]){
  30.             row_boom[rr] = true;
  31.             col_boom[cc] = true;
  32.             cnt++;
  33.         }
  34.     }
  35.     // 4) 输出剩余元素
  36.     for(int i = 1; i <= n; i++){
  37.         if(row_boom[i]) continue;
  38.         bool first = true;
  39.         for(int j = 1; j <= m; j++){
  40.             if(col_boom[j]) continue;
  41.             if(!first) cout << ' ';
  42.             cout << mat[i][j];
  43.             first = false;
  44.         }
  45.         if(!first) cout << '\n';
  46.     }
  47.     return 0;
  48. }
复制代码
L2-051 满树的遍历

题目
先将输入的全括号算式分析成一棵二叉树,然后做后序遍历——即先处理左子树、再处理右子树、末了输出当前节点的利用。输出时,假如左右子节点是叶子数字,就打印该数字;否则不打印。这样完全符合题目要“只输出数字+利用符”的格式要求。
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. struct Node {
  4.     // 如果 isLeaf,则 val 存数字字符串;否则存操作符 op,以及左右子节点指针
  5.     bool isLeaf;
  6.     string val;
  7.     char op;
  8.     Node *l, *r;
  9.     Node(string v): isLeaf(true), val(move(v)), op(), l(nullptr), r(nullptr) {}
  10.     Node(char c, Node* L, Node* R): isLeaf(false), val(), op(c), l(L), r(R) {}
  11. };
  12. string s;
  13. int pos;
  14. // 解析函数:根据语法 expr = '(' expr op expr ')' | number
  15. Node* parse() {
  16.     if (s[pos] == '(') {
  17.         ++pos; // skip '('
  18.         Node* L = parse();
  19.         char oper = s[pos++];
  20.         Node* R = parse();
  21.         ++pos; // skip ')'
  22.         return new Node(oper, L, R);
  23.     } else {
  24.         // 读数字
  25.         int start = pos;
  26.         while (pos < (int)s.size() && isdigit(s[pos])) ++pos;
  27.         return new Node(s.substr(start, pos - start));
  28.     }
  29. }
  30. // 后序遍历,按题目要求输出每一步
  31. void dfs(Node* cur) {
  32.     if (cur->isLeaf) return;
  33.     dfs(cur->l);
  34.     dfs(cur->r);
  35.     // 下面输出:如果左是叶子,先打印数字;然后打印操作符;如果右是叶子,再打印数字
  36.     if (cur->l->isLeaf) cout << cur->l->val;
  37.     cout << cur->op;
  38.     if (cur->r->isLeaf) cout << cur->r->val;
  39.     cout << "\n";
  40. }
  41. int main(){
  42.     ios::sync_with_stdio(false);
  43.     cin.tie(nullptr);
  44.     // 读入整行
  45.     if (!getline(cin, s)) return 0;
  46.     pos = 0;
  47.     Node* root = parse();
  48.     dfs(root);
  49.     return 0;
  50. }
复制代码
L2-054 三点共线

题目
可以使用 bitset 优化枚举过这道题。
功能bitsetunordered_set<int>插入/查询速率O(1) (硬件位利用)O(1) 均派(有哈希冲突)空间占用1 bit/值(非常省)至少 8 字节/值 + 哈希桶是否能负数索引❌ 必要 偏移量映射✅ 不限定值域

  • bitset 的根本用法
  1. #include <bitset>
  2. bitset<10> b;      // 创建一个包含10位的bitset,默认全是0
  3. b[3] = 1;          // 将第4位设为1(下标从0开始)
  4. b.set(5);          // 将第6位设为1
  5. b.reset(3);        // 将第4位设为0
  6. b.flip();          // 所有位取反
  7. bool x = b.test(5); // 判断第6位是否为1(返回true/false)
  8. int cnt = b.count(); // 返回有多少位是1
复制代码


  • Code
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int D = 1e6;  // 坐标偏移量
  4. bitset<2000010> pos; // 存储y=2的点
  5. int main() {
  6.     ios::sync_with_stdio(false);
  7.     cin.tie(nullptr);
  8.    
  9.     vector<vector<int>> layers(2);  // layers[0]:y=0, layers[1]:y=1
  10.     int n, xpmclzjkln = 0;  // 题目要求的中间变量
  11.    
  12.     cin >> n;
  13.     for (int i = 0; i < n; ++i) {
  14.         int x, y;
  15.         cin >> x >> y;
  16.         if (y == 2) {
  17.             pos.set(x + D);  // 坐标偏移防止负数
  18.         } else {
  19.             layers[y].push_back(x);
  20.         }
  21.     }
  22.     // 去重排序
  23.     for (auto& layer : layers) {
  24.         sort(layer.begin(), layer.end());
  25.         layer.erase(unique(layer.begin(), layer.end()), layer.end());
  26.     }
  27.     vector<pair<int, int>> ans;
  28.     for (int x0 : layers[0]) {
  29.         for (int x1 : layers[1]) {
  30.             int x2 = 2 * x1 - x0;
  31.             if(x2 < -1E6 || x2 > 1E6) continue;
  32.             if (pos.test(x2 + D)) {
  33.                 ans.emplace_back(x0, x1);
  34.             }
  35.         }
  36.     }
  37.     // 按要求排序
  38.     sort(ans.begin(), ans.end(), [](auto& a, auto& b) {
  39.         return tie(a.second, a.first) < tie(b.second, b.first);
  40.     });
  41.     // 输出结果
  42.     if (ans.empty()) {
  43.         cout << -1;
  44.     } else {
  45.         for (auto& [x0, x1] : ans) {
  46.             printf("[%d, 0] [%d, 1] [%d, 2]\n",
  47.                   x0, x1, 2*x1 - x0);
  48.         }
  49.     }
  50.     return 0;
  51. }
复制代码
L2-055 胖达的山头

差分取 max
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. using ll = long long;
  4. int parse_time(const string &s) {
  5.     // "hh:mm:ss" -> 秒数
  6.     int hh = stoi(s.substr(0,2));
  7.     int mm = stoi(s.substr(3,2));
  8.     int ss = stoi(s.substr(6,2));
  9.     return hh*3600 + mm*60 + ss;
  10. }
  11. int main(){
  12.     ios::sync_with_stdio(false);
  13.     cin.tie(nullptr);
  14.     int n;
  15.     cin >> n;
  16.     vector<pair<int,int>> events;
  17.     events.reserve(2*n);
  18.     string s_start, s_end;
  19.     for(int i = 0; i < n; i++){
  20.         cin >> s_start >> s_end;
  21.         int st = parse_time(s_start);
  22.         int ed = parse_time(s_end);
  23.         // [st, ed] 包含端点,故在 ed+1 时做 −1
  24.         events.emplace_back(st, +1);
  25.         events.emplace_back(ed+1, -1);
  26.     }
  27.     // 按时间排序
  28.     sort(events.begin(), events.end(),
  29.          [](auto &a, auto &b){
  30.              if(a.first != b.first)
  31.                  return a.first < b.first;
  32.              return a.second < b.second; // +1 也可以先后都累加
  33.          });
  34.     int cur = 0, ans = 0;
  35.     for(auto &e : events){
  36.         cur += e.second;
  37.         ans = max(ans, cur);
  38.     }
  39.     cout << ans << "\n";
  40.     return 0;
  41. }
复制代码
L2-056 被n整除的n位数

题目

  • DFS 构造每一位


  • 用 dfs(pos, prefix) 表现我们已经确定了前 pos-1 位,当前前缀值为 prefix(十进制整数)。
  • 若 pos > n,阐明前 n 位都已满足条件,检查这个 prefix 是否在区间 [a, b] 内,假如则生存。

  • 剪枝条件


  • 对于第 pos 位(1-based,下同),我们尝试的数字 d 必须使得:
                                         (                            p                            r                            e                            f                            i                            x                            ×                            10                            +                            d                            )                                                    m                                  o                                  d                                                  p                            o                            s                            =                            0.                                  (prefix \times 10 + d) \bmod pos = 0.                     (prefix×10+d)modpos=0.


  • 别的,第 1 位 pos=1 只能枚举 1..9(最高位不能为 0);后续可枚举 0..9,但按照提示:若 pos=n,即剩下末了一位,还要满足「能被 n 整除」,同样由上式天然保证。

  • 数值范围


  • n <= 14 时,深度 DFS 的分支被整除条件严酷限定,一般仅产生几十到几百个候选,远小于暴力                                         1                                       0                               n                                            10^n                     10n。
  • 用 long long 存前缀、比力区间,安全无溢出。
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. using ll = long long;
  4. int n;
  5. ll A, B;
  6. vector<ll> answer;
  7. // DFS 生成
  8. void dfs(int pos, ll prefix) {
  9.     if (pos > n) {
  10.         // 构造了 n 位数,检查区间
  11.         if (prefix >= A && prefix <= B) {
  12.             answer.push_back(prefix);
  13.         }
  14.         return;
  15.     }
  16.     int start = (pos == 1 ? 1 : 0);
  17.     for (int d = start; d <= 9; d++) {
  18.         ll nxt = prefix * 10 + d;
  19.         // 前 pos 位能被 pos 整除
  20.         if (nxt % pos == 0) {
  21.             dfs(pos + 1, nxt);
  22.         }
  23.     }
  24. }
  25. int main(){
  26.     ios::sync_with_stdio(false);
  27.     cin.tie(nullptr);
  28.     cin >> n >> A >> B;
  29.     answer.clear();
  30.     // n 位数的最小与最大
  31.     ll low = 1;
  32.     for (int i = 1; i < n; i++) low *= 10;
  33.     ll high = low * 10 - 1;
  34.     // 如果 [A,B] 与 n 位数区间无交集,直接无解
  35.     if (B < low || A > high) {
  36.         cout << "No Solution\n";
  37.         return 0;
  38.     }
  39.     // 交集后再 DFS,会节省一点无谓判断
  40.     A = max(A, low);
  41.     B = min(B, high);
  42.     dfs(1, 0LL);
  43.     if (answer.empty()) {
  44.         cout << "No Solution\n";
  45.     } else {
  46.         sort(answer.begin(), answer.end());
  47.         for (ll x : answer) {
  48.             cout << x << "\n";
  49.         }
  50.     }
  51.     return 0;
  52. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

刘俊凯

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表