ABC328 现场

image.png

被所有人吊打,bykem 20min 切到 G,找时间强迫他 v 个挂。

失误比较多,做太慢了,手速选手变成老人是这样的。

场切

A

portal

题意:给定一个长度为 \(n\) 的序列 \(s\),求其中不超过 \(x\) 的数之和。

Solution

直接特判,加进答案就行了。

这里我脑子炸了,对序列 \(s\) 排序后 upper_bound 找到第一个大于 \(x\) 的数,然后 accumulate 一下。当时孩子认为做的比较快,难绷。

\(\\\)

Code
// stODDDDDDDDDDDDDDDDDDDDDDDDDDD hzt CCCCCCCCCCCCCCCCCCCCCCCCCOrz

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 8 + 1;

int n, x;
int s[kN];

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin >> n >> x;
  for (int i = 1; i <= n; i++) {
    cin >> s[i];
  }
  sort(s + 1, s + n + 1);
  cout << accumulate(s + 1, upper_bound(s + 1, s + n + 1, x), 0ll) << '\n';
  return 0;
}

B

portal

题意:有 \(n\) 个月,每个月有 \(d_i\) 天,问有多少个日期可以使用同一个数字表示?

Solution

可以直接枚举这个同一个数字,然后统计答案贡献即可。

我考场上的时候的机翻比较烂,碰巧我 ABC 很少看原文。于是顶着脑子里的错误题意调成了正确代码,其实是写错了一个地方。

傻逼有道翻译。

\(\\\)

Code
// stODDDDDDDDDDDDDDDDDDDDDDDDDDD hzt CCCCCCCCCCCCCCCCCCCCCCCCCOrz

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 100 + 1;

int n;

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin >> n;
  int ans = 0;
  for (int i = 1, d; i <= n; i++) {
    cin >> d;
    if (i < 10) {
      if (d >= i) {
        ans++;
      }
      if (d >= 10 * i + i) {
        ans++;
      }
    } else if (i > 1 && i / 10 == i % 10) {
      if (d >= i % 10) {
        ans++;
      }
      if (d >= i) {
        ans++;
      }
    }
  }
  cout << ans << '\n';
  return 0;
}

C

portal

题意:给定一个长度为 \(n\) 的字符串 \(s\),有 \(q\) 次询问,求区间相邻相等字符位置个数。

Solution

直接对相邻相等位置前缀和一下就好了。

第一道没有失误的题。

\(\\\)

Code
// stODDDDDDDDDDDDDDDDDDDDDDDDDDD hzt CCCCCCCCCCCCCCCCCCCCCCCCCOrz

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 3e5 + 1;

int n, q;
string s;
int a[kN];

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin >> n >> q >> s, s = '#' + s;
  for (int i = 2; i <= n; i++) {
    a[i] = a[i - 1];
    if (s[i] == s[i - 1]) {
      a[i]++;
    }
  }
  for (int _ = 1, l, r; _ <= q; _++) {
    cin >> l >> r;
    cout << a[r] - a[l] << '\n';
  }
  return 0;
}

D

portal

题意:给定一个字符串 \(s\),每次找到最左端出现的 "ABC" 子串删除。问操作至无法操作后的字符串。

Solution

把字符从左往右加入栈中,"ABC" 一定是栈顶的连续三个字符。

\(\\\)

Code
// stODDDDDDDDDDDDDDDDDDDDDDDDDDD hzt CCCCCCCCCCCCCCCCCCCCCCCCCOrz

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;
using LL = long long;
using PII = pair<int, int>;

int n;
string s;
vector<char> v;

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin >> s;
  n = s.size(), s = '#' + s;
  v.emplace_back(0);
  for (int i = 1, c = 0; i <= n; i++) {
    v.emplace_back(s[i]), c++;
    if (c >= 3 && v[c - 2] == 'A' && v[c - 1] == 'B' && v[c] == 'C') {
      v.pop_back(), v.pop_back(), v.pop_back();
      c -= 3;
    }
  }
  for (int i = 1; i < v.size(); i++) {
    cout << v[i];
  }
  return 0;
}

E

portal

题意:给定一个 \(n\) 个点 \(m\) 条边的无向联通图,求他在 \(\mod k\) 意义下的最小生成树。

Solution

数据范围这么小,直接爆搜连哪些边即可。

为了防止连出环,并查集判一下即可。其实可以用可撤销并查集加上按秩合并省掉一个 \(n\)

\(\\\)

Code

// stODDDDDDDDDDDDDDDDDDDDDDDDDDD hzt CCCCCCCCCCCCCCCCCCCCCCCCCOrz

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 1e5 + 1;

LL n, m, p;
LL x[kN], y[kN], w[kN];
LL t[kN], fa[kN], ans = 1e18;

LL R(int x) {
  if (x == fa[x]) {
    return x;
  }
  fa[x] = R(fa[x]);
  return fa[x];
}

void D(LL k, LL c, LL d) {
  if (d == n - 1 || m - k + 1 < n - 1 - d) {
    if (m - k + 1 < n - 1 - d) {
      return;
    }
    int f = 0;
    iota(fa, fa + n + 1, 0);
    for (int i = 1; i <= m; i++) {
      if (t[i]) {
        if (R(x[i]) == R(y[i])) {
          f = 1;
        } else {
          fa[R(x[i])] = R(y[i]);
        }
      }
    }
    if (!f) {
      ans = min(ans, c);
    }
    return;
  }
  t[k] = 1, D(k + 1, (c + w[k]) % p, d + 1);
  t[k] = 0, D(k + 1, c, d);
}

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin >> n >> m >> p;
  for (int i = 1; i <= m; i++) {
    cin >> x[i] >> y[i] >> w[i];
  }
  D(1, 0, 0);
  cout << ans << '\n';
  return 0;
}

F

portal

题意:给定 \(q\) 个三元组 \((a_i, b_i, d_i)\),按顺序考虑,如果存在一个序列 \(x\) 使之前选中的以及当前这个三元组所表示的条件 \(x_{a_i} - x_{b_i} = d_i\),那么就选中当前三元组。问最后选择了哪些三元组?

Solution

考虑并查集维护互相数值关系确定的连通块。\(fa_i\) 表示 \(i\) 的祖先,令 \(g_i = x_i - x_{fa_i}\)。然后合并时和路径压缩时更新 \(fa\)\(g\) 即可。

考虑加入 \(x_i - x_j = k\) 这个条件。发现只有 \(i\)\(j\) 在同一个连通块内且 \(g_i - g_j != k\) 时不可加入限制。合并时考虑把 \(j\) 并向 \(i\)。有 \(x_{fa_j} = x_j - g_j, x_j = x_i - k, x_i = x_{fa_i} + g_i\)\(x_{fa_j} = x_{fa_i} + g_i - k - g_j\)\(g_{fa_i} = g_i - g_j - k\)。但是在 \(j\) 连向 \(i\)\(j\) 连通块内的其他点的 \(g\) 没有被重新计算。但是这件事情可以在路径压缩的时候完成:\(g_c\) 就等于 \(c\) 在连通块内路径压缩的道路上的点的 \(g\) 之和。

其实可以套个按秩合并,优化到反阿克曼。懒得再想了。

\(\\\)

Code
// stODDDDDDDDDDDDDDDDDDDDDDDDDDD hzt CCCCCCCCCCCCCCCCCCCCCCCCCOrz

#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>

using namespace std;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 2e5 + 1;

int n, q;
int fa[kN];
LL p[kN];

int R(int x) {
  if (x == fa[x]) {
    return x;
  }
  int v = fa[x];
  fa[x] = R(fa[x]);
  p[x] += p[v];
  return fa[x];
}
bool M(int x, int y, int w) {
  int fx = R(x), fy = R(y);
  if (fx == fy) {
    return p[x] - p[y] == w;
  }
  fa[fy] = fx;
  p[fy] = p[x] - p[y] - w;
  return 1;
}

int main() {
  cin.tie(0)->sync_with_stdio(0);
  cin >> n >> q;
  iota(fa, fa + n + 1, 0);
  for (int _ = 1, a, b, d; _ <= q; _++) {
    cin >> a >> b >> d;
    if (M(a, b, d)) {
      cout << _ << ' ';
    }
  }
  return 0;
}
posted @ 2023-11-12 23:38  Lightwhite  阅读(60)  评论(0)    收藏  举报