20240902

Room Temperature

我们首先可以发现他的初始适宜温度是无关紧要的(因为我们可以让他穿非常多的衣服,然后后续的操作就等于脱衣服),然后我们将数组统一模 \(T\),再排序,假设现在我们考虑第 \(i\) 个人,那么一定可以通过脱衣服,让温度在 \(a[i]\)\(a[i - 1] + t\) 内,然后我们要注意 \(i = 1\) 那么就是 \(a[1]\)\(a[n]\) 之内

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int N = 1e7 + 5;

int n, t, a[N], ans = 1e18;

signed main() {
  cin >> n >> t;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
    a[i] %= t;
  }
  sort(a + 1, a + n + 1);
  for (int i = 1; i <= n; i++) {
    a[i + n] = a[i] + t;
  }
  for (int i = 1; i <= n; i++) {
    int tmp = (a[i] + a[i + n - 1] + 1) / 2;
    ans = min(ans, max(tmp - a[i], a[i + n - 1] - tmp));
  }
  cout << ans;
  return 0;
}

Construction Project 2

首先假如最短路已经满足要求了,那么就可以直接输出即可,接下来猜一个结论架设我们只要统计对于一个点来说的 \(dis[1][a] + l + dis[b][n] <= k\) 的个数和就是答案,那么有一个问题就是如果有一条边使得 \(dis[1][b] + l + dis[a][n] <= k\) 怎么办,如果按照以上方法就会统计两遍,假设如果 \(dis[1][b] != dis[1][a] + l\) 那么 \(dis[1][a] + l + dis[b][n] <= dis[1][b] + dis[b][n]\) 也就是说 \(dis[1][n] <= k\) 那么就和最开始的条件矛盾了,然而假如 \(dis[1][b] = dis[1][a] + l\) 那么, \(dis[1][a] + l + l + dis[a][n] <= k\) 那么也与最初条件矛盾,所以也就是说如果 \(dis[1][a] + l + dis[b][n] <= k\)\(dis[1][b] + l + dis[a][n] <= k\) 中只会有一个满足条件,所以直接从 \(1\)\(n\) 分别跑一次再做一个双指针即可

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int N = 2e5 + 5;

struct node {
  int v, w;
};

struct F {
  int d, v;
  bool operator < (const F &_y) const {
    return d > _y.d;
  }
};

int n, m, s, t, l, k, dis[2][N], ans;

vector<node> g[N];

void dij(int x, int op) {
  priority_queue<F> q;
  q.push({0, x});
  dis[op][x] = 0;
  while (!q.empty()) {
    if (dis[op][q.top().v] < q.top().d) {
      q.pop();
      continue;
    }
    F cur = q.top();
    q.pop();
    for (auto e : g[cur.v]) {
      int v = e.v, w = e.w;
      if (dis[op][v] > dis[op][cur.v] + w) {
        dis[op][v] = dis[op][cur.v] + w;
        q.push({dis[op][v], v});
      }
    }
  }
}

signed main() {
  cin >> n >> m >> s >> t >> l >> k;
  for (int i = 1, u, v, w; i <= m; i++) {
    cin >> u >> v >> w;
    g[u].push_back({v, w});
    g[v].push_back({u, w});
  }
  memset(dis, 0x3f, sizeof(dis));
  dij(s, 0);
  dij(t, 1);
  if (dis[0][t] <= k) {
    cout << (n * (n - 1)) / 2 << "\n";
    return 0;
  }
  sort(dis[0] + 1, dis[0] + n + 1);
  sort(dis[1] + 1, dis[1] + n + 1);
  for (int i = 1, j = n; i <= n; i++) {
    while (j >= 1 && dis[0][i] + dis[1][j] + l > k) {
      j--;
    }
    ans += j;
  }
  cout << ans;
  return 0;
}

Marathon Race 2

我们可以把拿球改为放球,那么我们可以得出一个结论:放球时能放就放(当然终点与起点也会反过来)
先考虑 \(n <= 5000\) 时的做法,我们可以想到一个区间 \(dp\) 的状态, \(dp[i][j][0/1]\) 表示当前还没有放球的区间,当前在左端点还是右端点.但是不难发现这样设计会有一个缺陷,那就是当终点并不在一个球上时无法考虑所以我们还要再来一维表示最开始是从哪边开始放的
我们考虑最优情况下有 \(m\) 个不同位置的球(也就是离散化过后)放完时最少要走多少步,显然是 \(m * (m + 1) / 2\) 可是步数范围是 \(1\)\(500000\) 所以如果说 \(m >= 5000\) 就可以直接输出 \("NO"\) 了,所以就转化为了 \(n <= 5000\) 的做法

#include <bits/stdc++.h>

using namespace std;

#define int long long

const int N = 5e3 + 5, INF = 1e18;

int n, m, l, q, x[500005], sum[500005], dp[N][N][2][2], cnt[500005], s, g, t;

int query(int l, int r) {
  return sum[r] - sum[l - 1];
}

void Solve() {
  cin >> s >> g >> t;
  int p = lower_bound(x + 1, x + m + 2, g) - x, ans = 1e18;
  for (int i : {0, 1}) {
    int pos;
    if (i == 0) {
      pos = x[1];
    }
    else pos = x[m];
    if (p <= m) {
      ans = min(ans, dp[p][p][0][i] + (x[p] - g) * (sum[m] + 1) + abs(s - pos));
      ans = min(ans, dp[p][p][1][i] + (x[p] - g) * (sum[m] + 1) + abs(s - pos));
    }
    if (p >= 1) {
      ans = min(ans, dp[p - 1][p - 1][0][i] + (g - x[p - 1]) * (sum[m] + 1) + abs(s - pos));
      ans = min(ans, dp[p - 1][p - 1][1][i] + (g - x[p - 1]) * (sum[m] + 1) + abs(s - pos));
    }
  }
  ans += sum[m];
  if (ans <= t) {
    cout << "Yes\n";
  }
  else cout << "No\n";
}

signed main() {
  ios::sync_with_stdio(0);
  cin.tie(0);
  cin >> n >> l;
  for (int i = 1, a; i <= n; i++) {
    cin >> a;
    cnt[a]++;
  }
  for (int i = 0; i <= l; i++) {
    if (!cnt[i]) {
      continue;
    }
    x[++m] = i;
    sum[m] = sum[m - 1] + cnt[i];
  }
  x[m + 1] = 1e18;
  cin >> q;
  if (m >= 5000) {
    for (int i = 1; i <= q; i++) {
      cout << "NO\n";
    }
    return 0;
  }
  memset(dp, 0x3f, sizeof(dp));
  dp[1][m][0][1] = dp[1][m][1][0] = x[m] - x[1];
  dp[1][m][0][0] = dp[1][m][1][1] = 0;
  for (int len = m - 1; len >= 1; len--) {
    for (int l = 1, r = len; r <= m; l++, r++) {
      for (int i : {0, 1}) {
        int tmp = (n - query(l, r) + 1);
        if (l >= 2) {
          dp[l][r][0][i] = min(dp[l][r][0][i], dp[l - 1][r][0][i] + (x[l] - x[l - 1]) * tmp);
          dp[l][r][1][i] = min(dp[l][r][1][i], dp[l - 1][r][0][i] + (x[r] - x[l - 1]) * tmp);
        }
        if (r <= m - 1) {
          dp[l][r][0][i] = min(dp[l][r][0][i], dp[l][r + 1][1][i] + (x[r + 1] - x[l]) * tmp);
          dp[l][r][1][i] = min(dp[l][r][1][i], dp[l][r + 1][1][i] + (x[r + 1] - x[r]) * tmp);
        }
      }
    }
  }
  while (q--) {
    Solve();
  }
  return 0;
}
/*

*/

posted @ 2024-09-25 12:04  libohan0518  阅读(31)  评论(0)    收藏  举报