2023年第14届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组

2023年第14届蓝桥杯大赛软件赛省赛 C/C++ 大学 B 组

试题:第十四届蓝桥杯大赛软件赛省赛_CB.pdf
https://www.aliyundrive.com/s/VCX3wGSUBmd

试题 A: 日期统计(5)

直接暴力,8个for + 优化。
答案:235

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;

int mon[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
int n = 100, a[110], st[13][33];

int main() {
  freopen("in.txt", "r", stdin);
//  freopen("out.txt", "w", stdout);
  for (int i = 1; i <= n; i++) cin >> a[i];

  for (int y1 = 1; y1 <= n-7; y1++) {
    if (a[y1] != 2) continue;
    for (int y2 = y1+1; y2 <= n-6; y2++) {
      if (a[y2] != 0) continue;
      for (int y3 = y2+1; y3 <= n-5; y3++) {
        if (a[y3] != 2) continue;
        for (int y4 = y3+1; y4 <= n-4; y4++) {
          if (a[y4] != 3) continue;
          for (int m1 = y4+1; m1 <= n-3; m1++) {
            for (int m2 = m1+1; m2 <= n-2; m2++) {
              int mm = a[m1] * 10 + a[m2];
              if (mm < 1 || mm > 12) continue;
              if(st[mm][0]==mon[mm]) continue;
              for (int d1 = m2+1; d1 <= n-1; d1++) {
                for (int d2 = d1+1; d2 <= n; d2++) {
                  int dd = a[d1] * 10 + a[d2];
                  if (dd >= 1 && dd <= mon[mm]) {
                    if(!st[mm][dd]) st[mm][0] ++;
                    st[mm][dd] = 1;
                  }
                }
              }
            }
          }
        }
      }
    }
  }
  int ans = 0;
  for (int i = 1; i <= 12; i++)
    for (int j = 1; j <= mon[i]; j++) ans += st[i][j];
  cout << ans << endl;
  return 0;
}

试题 B: 01 串的熵(5)

化简公式 \(h(s) = -\sum_0^1{(t_i*p_i*log_2(p_i))}\),枚举 0 的数量,判断是否合法
答案:11027421

关于 \(log\)的求法:库中给出了

log(x);   // 以常数 e为底
log10(x); // 以 10为底
log2(x);  // 以 2为底

如果要求以 a 为底 b的对数:\(log_{a}(b)\)
可以利用:\(log_{a}(b)= \frac{log_c(b)}{log_c(a)} =log(b)/log(a)\)

C++参考手册:https://zh.cppreference.com/w/cpp/numeric/math

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;

int main() {
  int n = 23333333;
  double xs = 11625907.5798;
  for (int i = 0; i <= n/2; i++) {
    int t0 = i, t1 = n - i;
    double p0 = 1.0 * t0 / n, p1 = 1 - p0;
    double s0 = -t0 * p0 * log(p0) / log(2);
    double s1 = -t1 * p1 * log(p1) / log(2);
    if (abs(s0 + s1 - xs) <= 1e-4) {
      cout << t0;
    }
  }
  return 0;
}

试题 C: 冶炼金属(10)

二分答案

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
int n, a[N], b[N];
bool chk1(int x) {
  for (int i = 1; i <= n; i++)
    if (a[i] / x > b[i]) return 0;
  return 1;
}
bool chk2(int x) {
  for (int i = 1; i <= n; i++)
    if (a[i] / x < b[i]) return 0;
  return 1;
}

int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++)
      scanf("%d%d", &a[i], &b[i]);

  int l = 1, r = 1e9, ans1, ans2;
  while (l < r) {
    int mid = l + r >> 1;
    if (chk1(mid)) r = mid;
    else l = mid + 1;
  }
  ans1 = r, l = 1, r = 1e9;
  while (l < r) {
    int mid = l + r + 1 >> 1;
    if (chk2(mid)) l = mid;
    else r = mid - 1;
  }
  ans2 = l;
  printf("%d %d\n", ans1, ans2);
  return 0;
}

试题 D: 飞机降落(10)

贪心,按照最晚下落时间点升序,下落时长降序排序,依次停放,
正确性未证明,对拍了一下,wa了。

N≤10,枚举所有排列,判断是否有合法的排列,复杂度 \(O(n!*n*t)\)
3e8的计算量大概1s,题目限制2s。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
struct T {
  int t, d, l;
  bool operator<(const T& r) const {
    if (t + d != r.t + r.d) return t + d < r.t + r.d;
    return l < r.l;
  }
} t[N];

int main1() {
  int T, n, a, b, c; scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
      scanf("%d%d%d", &a, &b, &c);
      t[i] = {a, b, c};
    }
    sort(t + 1, t + 1 + n);
    int te = t[1].t + t[1].l, f = 1;
    for (int i = 2; i <= n; i++) {
      if (te > t[i].t + t[i].d) { f = 0; break; }
      if (te < t[i].t) te = t[i].t;
      te += t[i].l;
    }
    printf("%s\n", f ? "YES" : "NO");
  }
  return 0;
}

int p[N];
int main() {
  int T, n, a, b, c; scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
      scanf("%d%d%d", &a, &b, &c);
      t[i] = {a, b, c}, p[i]=i;
    }
    int te=0, f=1;
    do {
      te=0, f=1;
      for(int j=1; j<=n; j++) {
        int i=p[j];
        if(te > t[i].t+t[i].d) { f=0; break; }
        if(te < t[i].t) te = t[i].t;
        te += t[i].l;
      }
      if(f) break;
    } while(next_permutation(p+1, p+1+n));
    printf("%s\n", f ? "YES" : "NO");
  }
  return 0;
}

试题 E: 接龙数列(15)

dp 求出其最长接龙子序列长度 m, n-m就是答案。

  • dp[i] 表示以第i个数结尾的最长接龙子序列长度
    dp[i] = dp[最后出现首元素的位置]+1;
    最长接龙子序列长度 m=max(dp[i])
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
int n,m;
string a;
int L[N], R[N], dp[N], last[200];
int main() {
  cin >> n;
  for (int i = 1; i <= n; i++) {
    cin >> a;
    L[i] = a[0], R[i] = a[a.size() - 1];
    dp[i] = dp[last[L[i]]] + 1;
    if (dp[i] > dp[last[R[i]]])
      last[R[i]] = i;
    m = max(m, dp[i]);
  }
  cout << n - m;
  return 0;
}

从选或不选的角度出发

  • dp[i] 表示以数字 i 结尾的最长接龙子序列长度
    x 表示 第 i 个数的第一个数字,y 表示第 i 个数字的最后一个数字
    dp[y] = max(dp[x]+1, dp[y]); // max(选,不选)
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
int n, m, dp[N];
string a;
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> a;
        int x = a[0] - '0', y = a[a.size() - 1] - '0';
        dp[y] = max(dp[x] + 1, dp[y]), m = max(m, dp[y]);
    }
    cout << n - m;
    return 0;
}

试题 F: 岛屿个数(15)

连通块,环,两次bfs即可

试题 G: 子串简写(20)

后缀和求c2的个数,遍历c1,加上对应后缀和(i+k-1),复杂度 \(O(n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
int k, a[N];
string s;
char c1, c2;

int main() {
  cin >> k >> s >> c1 >> c2;
  for (int i = s.size() - 1; i >= 0; i--)
    a[i] = a[i + 1] + (s[i] == c2);
  int i = s.find(c1);
  LL ans = 0;
  while (i != string::npos) {
    ans += a[i + k - 1];
    i = s.find(c1, i + 1);
  }
  cout << ans;
  return 0;
}

试题 H: 整数删除(20)

链表+一个可以做到排序nlogn的数据结构

试题 I: 景区导游(25)

LCA,1e5 的数据用倍增
dis[i] 表示 根节点到 i 的距离/花费。
两点(a,b)之间的花费 = \(dis[a]+dis[b]-2*dis[lca(a,b)];\)

先求出按顺序出发的总花费 s,当删除某个 A[i]时有三种情况

  1. \(i=1\),花费变化:减去 A[1]->A[2] 的花费;
  2. \(i=k\),花费变化:减去 A[k-1]->A[k] 的花费;
  3. \(i\in[2,k-1]\),花费变化:减去 A[i-1]->A[i],减去 A[i]->A[i+1],加上 A[i-1]->A[i+1] 的花费。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1e6 + 10, INF = 0x3f3f3f3f;
vector<pair<int, int> > g[N];
int n, k, a[N];

LL s, dis[N], ans[N];
int q[N], depth[N], p[N][22];
bool st[N];

void bfs(int rt) {
  depth[rt] = 1, q[0] = rt, st[rt] = 1;
  int hh = 0, tt = 0;
  while (hh <= tt) {
    int u = q[hh++];
    for (auto it : g[u]) {
      int v = it.first, w = it.second;
      if (st[v]) continue;
      depth[v] = depth[u] + 1;
      dis[v] = dis[u] + w;
      q[++tt] = v, st[v] = 1, p[v][0] = u;
      for (int k = 1; k <= 21; k++)
        p[v][k] = p[p[v][k - 1]][k - 1];
    }
  }
}
int lca(int a, int b) {
  if (depth[a] < depth[b]) swap(a, b);
  for (int k = 21; k >= 0; k--)
    if (depth[p[a][k]] >= depth[b]) a = p[a][k];
  if (a == b) return a;
  for (int k = 21; k >= 0; k--)
    if (p[a][k] != p[b][k]) a = p[a][k], b = p[b][k];
  return p[a][0];
}
LL dist(int a, int b) {
  return dis[a] + dis[b] - 2 * dis[lca(a, b)];
}
int main() {
  scanf("%d%d", &n, &k);
  for (int i = 1, u, v, t; i < n; i++) {
    scanf("%d%d%d", &u, &v, &t);
    g[u].push_back({v, t});
    g[v].push_back({u, t});
  }
  bfs(1);
  for (int i = 1; i <= k; i++) scanf("%d", &a[i]);
  for (int i = 2; i <= k; i++) s += dist(a[i - 1], a[i]);
  ans[1] = s - dist(a[1], a[2]);
  ans[k] = s - dist(a[k - 1], a[k]);
  for (int i = 2; i < k; i++)
    ans[i] = s - dist(a[i - 1], a[i]) - dist(a[i], a[i + 1])
               + dist(a[i - 1], a[i + 1]);
  for (int i = 1; i <= k; i++) printf("%lld ", ans[i]);
  return 0;
}

试题 J: 砍树(25)

posted @ 2023-04-08 23:10  HelloHeBin  阅读(1144)  评论(3编辑  收藏  举报