OOI XVIII

CF 1939 B

题目描述

有一些点和 \(N-1\) 次操作,每次会在点 \(u\) 上所有纸条的上方贴一张纸条 \(c_u\),在 \(v\) 上贴 \(c_v\),并在两个点之间建一条边权为 \(w_{u,v}\) 的边,这次操作必须满足 \(c_u+c_v\ge w_{u,v}\)

现在给你每个点上从上至下的纸条和所有边的边权,请给出一种加边方案或确定方案不存在。

思路

我们考虑从叶子结点一步一步贪心地往上推。我们可以从叶子结点开始,对于每个儿子找到最小的可以满足地纸条并使用即可。

空间复杂度 \(O(N)\),时间复杂度 \(O(N\log N)\)

代码

#include<bits/stdc++.h>
using namespace std;
using pii = pair<int, int>;

const int MAXN = 200001;

int n, q, d[MAXN], fid[MAXN];
vector<int> a[MAXN];
set<pii> s[MAXN];
vector<tuple<int, int, int>> e[MAXN];
vector<pii> edge;

void dfs(int u, int fa) {
  a[u].resize(e[u].size());
  for(auto [v, w, id] : e[u]) {
    if(v != fa) {
      fid[v] = id;
      dfs(v, u);
      auto it = s[u].lower_bound({w - s[v].begin()->first, 0});
      if(it == s[u].end()) {
        cout << "No";
        exit(0);
      }
      a[u][it->second] = id;
      s[u].erase(it);
    }
  }
}

void DFS(int u) {
  for(int x : a[u]) {
    if(!x) {
      cout << fid[u] << " ";
    }else {
      DFS(edge[x - 1].first == u ? edge[x - 1].second : edge[x - 1].first);
    }
  }
}

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> q;
  for(int i = 1, u, v, w; i < n; ++i) {
    cin >> u >> v >> w;
    e[u].emplace_back(v, w, i);
    e[v].emplace_back(u, w, i);
    edge.emplace_back(u, v);
    d[u]++, d[v]++;
  }
  for(int i = 1; i <= n; ++i) {
    for(int j = 1, x; j <= d[i]; ++j) {
      cin >> x;
      s[i].insert({x, d[i] - j});
    }
  }
  dfs(1, 0);
  cout << "Yes\n";
  DFS(1);
  return 0;
}

CF 1939 C

题目描述

\(k\) 个一模一样地栈,每个栈的第 \(i\) 个元素是一个种类为 \(A_i\) 的礼物。有若干个人,每个人都可以拿若干个礼物,只有拿完了前一个栈中的礼物,才能拿下一个栈的,并且只能从栈顶拿。但每个人拿的不同种类礼物数量不能超过 \(t\) 个,求至少要多少个人才能把礼物拿完。

思路

很明显一个人会拿所有能拿的,所以我们可以用双指针预处理出从每个礼物开始拿会拿到哪个礼物。使用倍增求解即可。

时空复杂度均为 \(O(N\log N)\)

代码

#include<bits/stdc++.h>
using namespace std;
using ll = long long;

const int MAXN = 600001;

int n, k, t, a[MAXN], tot, cnt[MAXN], f[61][MAXN];
ll g[61][MAXN], ans;
vector<int> ve;

int main() {
  ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  cin >> n >> k >> t;
  for(int i = 1; i <= n; ++i) {
    cin >> a[i];
    ve.emplace_back(a[i]);
  }
  sort(ve.begin(), ve.end()), ve.erase(unique(ve.begin(), ve.end()), ve.end());
  if(t >= ve.size()) {
    cout << 1;
    return 0;
  }
  for(int i = 1; i <= n; ++i) {
    a[i] = lower_bound(ve.begin(), ve.end(), a[i]) - ve.begin() + 1;
    if(a[i] != a[tot]) {
      a[++tot] = a[i];
    }
  }
  for(int i = 1; i <= tot; ++i) {
    a[tot + i] = a[i];
  }
  int res = 0;
  for(int i = 1, j = 1; i <= tot; --cnt[a[i]], res -= !cnt[a[i]], ++i) {
    for(; j <= 2 * tot && res + !cnt[a[j]] <= t; res += !cnt[a[j]], ++cnt[a[j++]]) {
    }
    f[0][i] = (j > tot ? j - tot : j);
    g[0][i] = (j > tot);
  }
  for(int i = 1; i <= 60; ++i) {
    for(int j = 1; j <= tot; ++j) {
      f[i][j] = f[i - 1][f[i - 1][j]];
      g[i][j] = g[i - 1][j] + g[i - 1][f[i - 1][j]];
    }
  }
  int x = 1;
  ll pos = 1;
  for(int i = 60; i >= 0; --i) {
    if(pos + g[i][x] <= k) {
      pos += g[i][x], x = f[i][x], ans += (1ll << i);
    }
  }
  res = 0;
  for(int i = 1; i <= n; ++i) {
    cnt[i] = 0;
  }
  for(int i = x, j = x; i <= tot; i = j) {
    for(; j <= tot && res + !cnt[a[j]] <= t; res += !cnt[a[j]], ++cnt[a[j++]]) {
    }
    ans++;
    res = 0;
    for(int p = i; p < j; ++p) {
      cnt[a[p]] = 0;
    }
  }
  cout << ans;
  return 0;
}
posted @ 2024-10-20 21:09  Yaosicheng124  阅读(4)  评论(0编辑  收藏  举报