专栏文章

2025 CCH非专业级软件能力认证提高级第十轮总结

个人记录参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@minm09zw
此快照首次捕获于
2025/12/02 04:36
3 个月前
此快照最后确认于
2025/12/02 04:36
3 个月前
查看原文
每日爆炸(5/1)
T3数据爆炸,std爆炸,T4数据爆炸,心态爆炸,pts爆炸
预期:100 + 100 + 看运气 + 50
实际:100 + 100 + 5 + 50

T1

题意:有一个数字 mm,每时刻可以将 mm 加一、减一或不变。有 nn 个时刻 tit_i,要求在 tit_ilimril_i \le m \le r_i,若有方案能满足所有要求,输出 YES,否则输出 NO
依旧先拉屎,回来再写。
发现只要记录当前可能温度最大值和最小值,如果与当前的范围不相交,就无解。否则就取个交集然后继续。
CPP
#include <bits/stdc++.h>

#define int long long

using namespace std;

const int kMaxN = 1e5 + 5;

struct node {
  int t, l, h;
} p[kMaxN];

int T, n, m;

bool cmp(node a, node b) {
  return a.t < b.t;
}

void solve() {
  cin >> n >> m;
  for (int i = 1; i <= n; i++)
    cin >> p[i].t >> p[i].l >> p[i].h;
  sort(p + 1, p + n + 1, cmp);
  int tl = m, tr = m;
  for (int i = 1; i <= n; i++) {
    tl -= (p[i].t - p[i - 1].t), tr += (p[i].t - p[i - 1].t);
    if (tr < p[i].l || tl > p[i].h) {
      cout << "NO\n";
      return;
    }
    tl = max(tl, p[i].l), tr = min(tr, p[i].h);
  }
  cout << "YES\n";
}

signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  for (cin >> T; T; T--) 
    solve();
  return 0;
}
又是30min,不知道为什么每一次一会T1就拉屎。

T2

题意:有一棵树,每个点上有一个数集,qq 次询问,每次求 xx 到根节点经过的最早的数集中包含 yy 的点的编号,没有的话输出 -1
看到范围感觉这题是 O(qlogn)\mathcal{O(q \log n)} 的,然后就想 log\log 算法,感觉不是很可做。
于是就想把询问离线处理。
我们可以存下每个点的询问的 yy 和是第几个询问,存完后直接暴搜,同时维护一个每个数出现的位置(只要记最后一个),然后把每个点的询问都处理了就可以了,不要忘了回溯。
CPP
#include <bits/stdc++.h>

using namespace std;

const int kMaxN = 1e5 + 5;

struct node {
  int v, id;
};

int n, fa[kMaxN], Q, ans[kMaxN], now[kMaxN];
vector<int> e[kMaxN], a[kMaxN];
vector<node> q[kMaxN];

void dfs(int x) {
  vector<int> v;
  for (int i = 0; i < a[x].size(); i++) {
    v.push_back(now[a[x][i]]);
    now[a[x][i]] = x;
  }
  for (int i = 0; i < q[x].size(); i++)
    ans[q[x][i].id] = now[q[x][i].v];
  for (int i = 0; i < e[x].size(); i++)
    dfs(e[x][i]);
  for (int i = 0; i < a[x].size(); i++)
    now[a[x][i]] = v[i];
}

int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n;
  for (int i = 2; i <= n; i++) {
    cin >> fa[i];
    e[fa[i]].push_back(i);
  }
  for (int i = 1, k; i <= n; i++) {
    for (cin >> k; k; k--) {
      int x;  
      cin >> x;
      a[i].push_back(x);
    }
  }
  cin >> Q;
  for (int i = 1; i <= Q; i++) {
    int x, y;
    cin >> x >> y;
    q[x].push_back({y, i});
  }
  memset(now, -1, sizeof(now));
  dfs(1);
  for (int i = 1; i <= Q; i++)
    cout << ans[i] << '\n';
  return 0;
}
竟然有人用数剖+倍增再加线段树过了,太恐怖了。

T4

题意:有一棵以 11 为根的树,每个节点有两个值 ai,bia_i,b_i,你可以从节点 xx 跳到它的子树内任意一个节点 yy 上,花费为 ax×bya_x \times b_y。跳跃多次走过一条路径的总费用为每次跳跃的费用之和。请分别计算出每个节点到达它子树中叶子节点的费用中的最小值。不能从一个节点跳到它自己。
暴力 O(n2)\mathcal{O(n^2)} dp很好做,于是在此基础上开始想转移优化。
想了1h想到了,兴奋地开始写的时候发现有 (105)105(10^5)^{10^5} 的乘法于是去世了,气炸了。
最后只能暴力遗憾离场。

T3

赛时写不动了,写完T4才来的。
后来发现是个广搜,直接死掉了。

评论

0 条评论,欢迎与作者交流。

正在加载评论...