「题解」Codeforces Round 980 (Div. 2)

before

\(A \sim D\) 的题解

A. Profitable Interest Rate

Problem

A. Profitable Interest Rate

Sol&Code

数学题,有 \(a - x \geq b - 2x\),得 \(x = b - a\)

特判 \(a \geq b\) 以及 \(a < x\) 的情况即可。

#include <bits/stdc++.h>

#define M 10001
#define N 100001

typedef long long ll;
typedef std::pair<int, int> pii;

int T, a, b;

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d %d", &a, &b);
    if (a >= b) printf("%d\n", a);
    else {
      int x = b - a;
      printf("%d\n", std::max(0, a - x));
    }
  }
  return 0;
}

B. Buying Lemonade

Problem

B. Buying Lemonade

Sol&Code

一种最优的策略是,首先对已知还有剩余的所有按钮按当前最少的那个次数,然后用一定的次数排除没有库存的按钮,重复执行上述步骤。

#include <bits/stdc++.h>

#define M 10001
#define N 200001

typedef long long ll;
typedef std::pair<int, int> pii;

int T, n, k, a[N];

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d %d", &n, &k);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    std::sort(a + 1, a + n + 1);
    long long ans = 0, now = 1, minu = 0;
    while (k > 0) {
      while (now < n && a[now] <= minu) ++now, ++ans;
      a[now] -= minu;
      minu += a[now];
      int t = std::min((long long)std::ceil(1.0 * k / a[now]), n - now + 1);
      ans += t * a[now];
      k -= t * a[now];
    }
    printf("%lld\n", ans + k);
  }
  return 0;
}

C. Concatenation of Arrays

Problem

C. Concatenation of Arrays

Sol&Code

考虑对于一定顺序排列的元组,交换当中相邻的两个元组,对于这俩两侧的元组贡献的逆序对数没有影响。

考虑这俩如何排序更优,按元组内的数据和从小到大排。

#include <bits/stdc++.h>

#define M 10001
#define N 100001

typedef long long ll;
typedef std::pair<int, int> pii;

int T, n;
struct Pair {
  int x, y, sum;
  friend bool operator < (Pair p1, Pair p2) {
    if (p1.sum != p2.sum) return p1.sum < p2.sum;
    return std::min(p1.x, p1.y) < std::min(p2.x, p2.y);
  }
}p[N];

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
      scanf("%d %d", &p[i].x, &p[i].y);
      p[i].sum = p[i].x + p[i].y;
    }
    std::sort(p + 1, p + n + 1);
    for (int i = 1; i <= n; ++i) printf("%d %d ", p[i].x, p[i].y);
    puts("");
  }
  return 0;
}

D. Skipping

Problem

D. Skipping

Sol&Code

发现答案最后一定是对于题目集的一段前缀减去跳过的题目。

于是考虑维护跳到题目 \(i\) 最少跳过多少分,对于 \(1\) 来说是 \(0\)。按照跳到 \(i\) 最少跳过的分数加上 \(i\) 的分数从小到大去更新更大的 \(i\)。用大根堆来做。

#include <bits/stdc++.h>

#define M 10001
#define N 400001
#define inf 100000000000000007

typedef long long ll;
typedef std::pair<ll, ll> pll;

bool used[N];
ll sum[N], skip[N];
int T, n, a[N], b[N];
std::priority_queue<pll> q;

int main() {
  scanf("%d", &T);
  while (T--) {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    for (int i = 1; i <= n; ++i) scanf("%d", &b[i]);
    for (int i = 1; i <= n; ++i) sum[i] = sum[i - 1] + a[i];
    for (int i = 1; i <= n; ++i) skip[i] = inf, used[i] = 0;

    skip[1] = 0;
    int nowp = 2;
    q.push({0 - a[1], 1});
    while (!q.empty()) {
      auto [x, y] = q.top();
      q.pop(); x = -x;
      if (b[y] <= y) continue;
      if (used[y]) continue;
      used[y] = true;
      for (int i = std::max((int)y + 1, nowp); i <= b[y]; ++i) {
        skip[i] = std::min(skip[i], (ll)x);
        q.push({0 - a[i] - skip[i], i});
      }
      nowp = std::max(nowp, b[y] + 1);
    }
    long long ans = -inf;
    for (int i = n; i >= 1; --i) ans = std::max(ans, sum[i] - skip[i]);
    printf("%lld\n", ans);
  }
  return 0;
}

After

唉唉,掉大分了。

posted @ 2024-10-21 15:02  yu__xuan  阅读(131)  评论(0编辑  收藏  举报