20230925 模拟赛总结

模拟赛连接

排名:\(\text{rank 1}\)
分数:\(100+100+100+100=400\)

集训期间第二次 AK!

T1:灭火 / fire

题目描述:

求出 \(n\) 个数 \(a_1,a_2,\dots,a_n\) 的和除以 \(m\) 向上取整的结果。(\(0<a_i,m<2^{63},0<n\le20\)

思路:

直接求和,然后向上取整即可,注意要用高精,我用的是 __int128(注意 __int128 的读入和输出都需要自行模拟)。

时间复杂度:\(O(n)\),空间复杂度:\(O(1)\)

代码:

#include <bits/stdc++.h>

using namespace std;

long long n, m, w;
__int128 ans;
string s;

int main() {
  freopen("fire.in", "r", stdin);
  freopen("fire.out", "w", stdout);
  for (cin >> n >> m; n; n--) {
    cin >> w, ans += w;
  }
  for (ans = (ans + m - 1) / m; ans; ans /= 10) {
    s = (char)(ans % 10 + '0') + s;
  }
  cout << s;
  return 0;
}

T2:数学题 / math

题目描述:

\(n\) 个自然数中任意取出两个数 \(a\)\(b\),保证这两个数满足 \(a \lt b\)。若存在一个自然数 \(c\)\(c\) 不一定属于这 \(n\) 个自然数),能够使得 \(a-c=c-b\),那么将 \((a, b)\) 视为一组可行的数对。(\(0 \lt n \le 100000,0 \lt x \lt 2^{63}\)

思路:

将方程变一下:\(a+b=2c\),也就是 \(a,b\) 的和要是偶数才行。我们知道同奇偶的数相加为偶数,所以我们可以先把那 \(n\) 个自然数去重,然后记录剩下的数的奇偶性,如果剩下的奇数有 \(x\) 个,偶数有 \(y\) 个,那么奇数集合里的可以随便组合(不可以两个数相同,且要满足 \(a<n\)),所以在奇数集合里的答案就是 \(\dfrac{x\cdot(x-1)}{2}\),偶数集合同理,所以总的答案就是 \(\dfrac{x\cdot(x-1)+y\cdot(y-1)}{2}\)

时间复杂度:\(O(n)\),空间复杂度:\(O(n)\)

代码:

#include <bits/stdc++.h>

using namespace std;
using LL = long long;

LL n, x, c[2], ans;
set<LL> s;

int main() {
  freopen("math.in", "r", stdin);
  freopen("math.out", "w", stdout);
  for (cin >> n; n; n--) {
    cin >> x, c[x & 1] += !s.count(x), s.insert(x);
  }
  cout << c[0] * (c[0] - 1) / 2 + c[1] * (c[1] - 1) / 2;
  return 0;
}

T3:蛋糕 / cake

题目描述:

桌上有一排 \(n\) 个蛋糕,每个蛋糕的口味可能不一样,用数字 \(1\) ~ \(m\) 来表示。我们可以通过指定一个区间 \([L,R]\) 来获取第 \(L\) 个至第 \(R\) 个蛋糕,此时区间长度 \(d\)\(R - L + 1\)

现在希望能够指定一个区间,使得每种口味的蛋糕都能获取到。

请问区间长度至少需要多长?(\(0 \lt n \le 100000, 0 \lt m \le 10000\))

思路:

一道很板子的题目,很明显的双指针,在双指针的过程中 \(cnt\) 记录当前区间的种类数,右指针不断右移,如果 \(cnt=m\),那么就左指针向右移,知道 \(cnt\lt m\) 为止,在循环内更新答案即可。

时间复杂度:\(O(n)\),空间复杂度:\(O(n)\)

代码:

#include <bits/stdc++.h>

using namespace std;

const int kMaxN = 1e5 + 5, kMaxM = 1e4 + 5;

int n, m, a[kMaxN], c[kMaxM], ans = 1e9;

int main() {
  freopen("cake.in", "r", stdin);
  freopen("cake.out", "w", stdout);
  cin >> n >> m;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
  }
  for (int l = 1, r = 1, cnt = 0; r <= n; r++) {
    for (cnt += !c[a[r]]++; cnt >= m; cnt -= !--c[a[l++]]) {
      ans = min(ans, r - l + 1);
    }
  }
  ans == 1e9 && (cout << "no answer");
  ans != 1e9 && (cout << ans);
  return 0;
}

T4:逃离 / escape

题目描述:

小 z 和小 m 被困在了一个庄园中,最初时分别处于两个不同的位置。他们各自拥有半条关键信息,当两人相遇时,就能够将信息凑完整,逃离庄园。

庄园的地形用一个 \(n\) 阶的 01 矩阵表示,0 表示空地,1 表示障碍。两人只能朝上下左右四个方向移动,每 \(1\) 秒可以移动一次,且在移动过程中只能停留在空地上,但两人都具有一个特殊的技能:

小 z 具有技能急速:每次移动可以走两步(允许这两步的方向不同,也允许不走第二步);

小 m 具有技能跳跃:若移动的方向为障碍且障碍后为空地,可借助障碍直接跳跃至空地。(具体能走到的位置可参考下图)

请编程计算两人相遇最少要花费多少秒。(\(0 \lt n \le 1000\))

思路:

这题很明显是个 bfs,由于小 z 和小 m 的技能不同考虑分开算。

对于小 z,他可以选择走一步或者在没墙的路径上走两步。对于小 m,他可以选择走一步,也可以选择在有墙的位置连续同一方向走两格。算出小 z 和小 m,到达每一个点的最短路径后,枚举相遇点,若小 z 和小 m 都可以走到那么就将两次时间取最大值,表示以这个点为相遇点的最短时间,然后更新答案即可。

时间复杂度:\(O(n^2)\),空间复杂度:\(O(n^2)\)

代码:

#include <bits/stdc++.h>

using namespace std;
using Pii = pair<int, int>;

const int kMaxN = 1005, dx[] = {0, 0, 1, -1}, dy[] = {1, -1, 0, 0};

int n, xa, ya, xb, yb, dis[2][kMaxN][kMaxN], ans = 1e9;
char c[kMaxN][kMaxN];

void R(int x, int y, int nx, int ny, queue<Pii> &q, int dis[kMaxN][kMaxN]) {
  if (!~dis[nx][ny] && c[nx][ny] == '0') {
    dis[nx][ny] = dis[x][y] + 1;
    q.push({nx, ny});
  }
}

void bfs1(int sx, int sy) {
  queue<Pii> q;
  memset(dis[0], -1, sizeof(dis[0]));
  for (R(0, 0, sx, sy, q, dis[0]); q.size(); q.pop()) {
    int x = q.front().first, y = q.front().second;
    for (int i = 0; i < 4; i++) {
      R(x, y, x + dx[i], y + dy[i], q, dis[0]);
      if (c[x + dx[i]][y + dy[i]] == '0') {
        for (int j = 0; j < 4; j++) {
          R(x, y, x + dx[i] + dx[j], y + dy[i] + dy[j], q, dis[0]);
        }
      }
    }
  }
}

void bfs2(int sx, int sy) {
  queue<Pii> q;
  memset(dis[1], -1, sizeof(dis[1]));
  for (R(0, 0, sx, sy, q, dis[1]); q.size(); q.pop()) {
    int x = q.front().first, y = q.front().second;
    for (int i = 0; i < 4; i++) {
      R(x, y, x + dx[i], y + dy[i], q, dis[1]);
      if (c[x + dx[i]][y + dy[i]] == '1') {
        R(x, y, x + 2 * dx[i], y + 2 * dy[i], q, dis[1]);
      }
    }
  }
}

int main() {
  freopen("escape.in", "r", stdin);
  freopen("escape.out", "w", stdout);
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> xa >> ya >> xb >> yb;
  for (int i = 1; i <= n; i++) {
    cin >> c[i] + 1;
  }
  bfs1(xa, ya), bfs2(xb, yb);
  for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= n; j++) {
      c[i][j] == '0' && ~dis[0][i][j] && ~dis[1][i][j] && (ans = min(ans, max(dis[0][i][j], dis[1][i][j])));
    }
  }
  ans == 1e9 && (cout << "no answer");
  ans != 1e9 && (cout << ans);
  return 0;
}
posted @ 2023-09-25 14:08  liruixiong0101  阅读(74)  评论(1编辑  收藏  举报