首页 > 其他分享 >Codeforces Round #826 (Div. 3)

Codeforces Round #826 (Div. 3)

时间:2022-10-13 00:22:12浏览次数:71  
标签:std unique color ++ Codeforces int vector Div 826

F. Multi-Colored Segments

观察: 如果某个位置上有大于等于两种不同的颜色,这个位置就可以更新任何颜色的线段的答案。

基于观察就可以通过模拟来解决问题了。

大概就是先离散话的处理一下,跑出每个位置上不同颜色的数量,以及如果这个位置上只有一种颜色,这个颜色是什么。

然后对于每个线段,有 3 种位置可以更新它的答案:

  1. 这个线段覆盖的位置
  2. 这个线段之前的位置
  3. 这个线段之后的位置

对于第 1 种位置,如果可以更新,那么这个线段上必定有超过一种颜色,这个就结合每个位置上不同颜色的数量以及前缀和处理一下就能搞。

对于第 2 种和第 3 种,就线性遍历一下就能跑出来了。以第 2 种为例,根据观察,只需要考虑之前至多两个位置就能包括所有的情况。

AC代码
// Problem: F. Multi-Colored Segments
// Contest: Codeforces - Codeforces Round #826 (Div. 3)
// URL: https://codeforces.com/contest/1741/problem/F
// Memory Limit: 256 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO \
  std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);

#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#define ASSERT(x) ;
#define serialize() std::string("")
#endif

using i64 = int64_t;
using u64 = uint64_t;

void Initialize();
void SolveCase(int Case);

int main(int argc, char* argv[]) {
  CPPIO;
  int T = 1;
  std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    SolveCase(t);
  }
  return 0;
}

void Initialize() {}

void SolveCase(int Case) {
  int n;
  std::cin >> n;

  std::vector<int> p(2 * n);
  std::vector<int> l(n), r(n), c(n);
  for (int i = 0; i < n; ++i) {
    int x, y, z;
    std::cin >> x >> y >> z;
    --z;

    l[i] = x;
    r[i] = y;
    c[i] = z;

    p[2 * i] = x;
    p[2 * i + 1] = y;
  }

  std::sort(p.begin(), p.end());
  p.erase(std::unique(p.begin(), p.end()), p.end());
  int m = p.size();
  for (int i = 0; i < n; ++i) {
    l[i] = std::lower_bound(p.begin(), p.end(), l[i]) - p.begin();
    r[i] = std::lower_bound(p.begin(), p.end(), r[i]) - p.begin();
  }

  std::vector<int> num_unique_color_at(m, 0);
  std::vector<int> unique_color_at(m, -1);
  std::vector<int> num_of_color(n, 0);
  int num_unique_color = 0;
  std::set<int> unique_colors;
  std::vector<std::vector<std::array<int, 2>>> color_start_at(m);
  std::vector<std::vector<std::array<int, 2>>> color_end_at(m);
  for (int i = 0; i < n; ++i) {
    logd(l[i], r[i], c[i]);
    color_start_at[l[i]].push_back({c[i], i});
    color_end_at[r[i]].push_back({c[i], i});
  }
  for (int i = 0; i < m; ++i) {
    std::sort(color_start_at[i].begin(), color_start_at[i].end());
    std::sort(color_end_at[i].begin(), color_end_at[i].end());
  }
  for (int i = 0; i < m; ++i) {
    for (auto [color, seg_id] : color_start_at[i]) {
      ++num_of_color[color];
      if (num_of_color[color] == 1) {
        logd(i, color);
        ++num_unique_color;
        unique_colors.insert(color);
      }
    }

    num_unique_color_at[i] = num_unique_color;
    if (num_unique_color == 1) {
      unique_color_at[i] = *unique_colors.begin();
    }

    for (auto [color, seg_id] : color_end_at[i]) {
      --num_of_color[color];
      if (num_of_color[color] == 0) {
        logd(i, color);
        --num_unique_color;
        unique_colors.erase(color);
      }
    }
  }
  std::vector<int> has_more_than_two_color(m, 0);
  for (int i = 0; i < m; ++i) {
    has_more_than_two_color[i] = num_unique_color_at[i] > 1;
  }
  std::vector<int> accumulate_h = has_more_than_two_color;
  for (int i = 1; i < m; ++i)
    accumulate_h[i] += accumulate_h[i - 1];
  logd(num_unique_color_at);
  logd(has_more_than_two_color);

  std::vector<int> ans(n, std::numeric_limits<int>::max());
  {
    for (int i = 0; i < n; ++i) {
      int L = l[i];
      int R = r[i];
      int S = accumulate_h[R] - (L == 0 ? 0 : accumulate_h[L - 1]);
      if (S > 0)
        ans[i] = 0;
    }
  }
  {
    // -1 stands for invalid, n stands for more than 2.
    int c1 = -1, i1 = -1;
    int c2 = -1, i2 = -1;
    for (int i = 0; i < m; ++i) {
      int unique_color_at_i = unique_color_at[i];
      for (auto [color, seg_id] : color_start_at[i]) {
        logd(color, seg_id, c1, i1, c2, i2);

        if (c1 != -1 && (c1 == n || color != c1)) {
          ans[seg_id] = std::min(ans[seg_id], p[i] - p[i1]);
        }
        if (c2 != -1 && (c2 == n || color != c2)) {
          ans[seg_id] = std::min(ans[seg_id], p[i] - p[i2]);
        }
      }

      if (has_more_than_two_color[i] || c1 != unique_color_at_i) {
        c2 = c1, i2 = i1;
        c1 = has_more_than_two_color[i] ? n : unique_color_at_i, i1 = i;
      } else {
        i1 = i;
      }
    }
  }
  {
    // -1 stands for invalid, n stands for more than 2.
    int c1 = -1, i1 = -1;
    int c2 = -1, i2 = -1;
    for (int i = m - 1; i >= 0; --i) {
      int unique_color_at_i = unique_color_at[i];
      for (auto [color, seg_id] : color_end_at[i]) {
        unique_color_at_i = color;

        if (c1 != -1 && (c1 == n || color != c1)) {
          ans[seg_id] = std::min(ans[seg_id], -p[i] + p[i1]);
        }
        if (c2 != -1 && (c2 == n || color != c2)) {
          ans[seg_id] = std::min(ans[seg_id], -p[i] + p[i2]);
        }
      }

      if (has_more_than_two_color[i] || c1 != unique_color_at_i) {
        c2 = c1, i2 = i1;
        c1 = has_more_than_two_color[i] ? n : unique_color_at_i, i1 = i;
      } else {
        i1 = i;
      }
    }
  }

  for (int i = 0; i < n; ++i)
    std::cout << ans[i] << " \n"[i + 1 == n];
}

G. Kirill and Company

做法1

注意到至多只有 \(6\) 个人没有车,所以建图跑费用流的话,至多跑 \(6\) 次增广之后就能得到答案。

AC代码
// Problem: G. Kirill and Company
// Contest: Codeforces - Codeforces Round #826 (Div. 3)
// URL: https://codeforces.com/contest/1741/problem/G
// Memory Limit: 256 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>

#define CPPIO \
  std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);

#ifdef BACKLIGHT
#include "debug.h"
#else
#define logd(...) ;
#define ASSERT(x) ;
#define serialize() std::string("")
#endif

using i64 = int64_t;
using u64 = uint64_t;

void Initialize();
void SolveCase(int Case);

int main(int argc, char* argv[]) {
  CPPIO;
  int T = 1;
  std::cin >> T;
  for (int t = 1; t <= T; ++t) {
    SolveCase(t);
  }
  return 0;
}

void Initialize() {}

template <typename DistanceType,
          typename Comp = std::greater<>,
          typename Edge = std::pair<DistanceType, int>,
          typename Node = std::pair<DistanceType, int>>
std::vector<DistanceType> Dijkstra(const std::vector<std::vector<Edge>>& g,
                                   int s) {
  const DistanceType INF = std::numeric_limits<DistanceType>::max();
  const int n = g.size();
  const Comp comp;

  std::vector<DistanceType> dis(n, INF);
  std::vector<bool> vis(n, false);

  std::priority_queue<Node, std::vector<Node>, Comp> q;
  dis[s] = 0;
  q.push(Node(dis[s], s));
  while (!q.empty()) {
    auto [c, u] = q.top();
    q.pop();

    if (vis[u])
      continue;
    vis[u] = true;

    for (auto [w, v] : g[u]) {
      if (comp(dis[v], c + w)) {
        dis[v] = c + w;
        q.push(Node(dis[v], v));
      }
    }
  }

  return dis;
}

template <typename CapacityType, typename CostType>
class MinCostMaxFlowGraph {
 private:
  struct Edge {
    int from, to;
    CapacityType capacity;
    CostType cost;
    Edge() {}
    Edge(int _from, int _to, CapacityType _capacity, CostType _cost)
        : from(_from), to(_to), capacity(_capacity), cost(_cost) {}
  };
  int n_;
  int m_;
  std::vector<Edge> edges_;
  std::vector<std::vector<int>> adjacent_;

 public:
  MinCostMaxFlowGraph(int n) : n_(n), m_(0), edges_(0), adjacent_(n) {}

  void AddEdge(int u, int v, CapacityType capacity, CostType cost) {
    assert(0 <= u and u < n_);
    assert(0 <= v and v < n_);

    edges_.push_back(Edge(u, v, capacity, cost));
    adjacent_[u].push_back(m_);
    ++m_;

    edges_.push_back(Edge(v, u, 0, -cost));
    adjacent_[v].push_back(m_);
    ++m_;
  }

  std::pair<CapacityType, CostType> EK(int src, int dst) {
    const static CapacityType INF = std::numeric_limits<CapacityType>::max();

    std::vector<CostType> h(n_);
    std::vector<bool> inq(n_);
    std::function<void()> spfa = [&]() -> void {
      std::fill(h.begin(), h.end(), INF);

      std::queue<int> q;
      q.push(src);
      inq[src] = true;
      h[src] = 0;
      while (!q.empty()) {
        int u = q.front();
        q.pop();
        inq[u] = false;

        for (int edge_id : adjacent_[u]) {
          auto [from, to, capacity, cost] = edges_[edge_id];
          if (capacity <= 0 || h[to] <= h[from] + cost)
            continue;
          h[to] = h[from] + cost;
          if (!inq[to]) {
            q.push(to);
            inq[to] = true;
          }
        }
      }
    };

    std::vector<CostType> d(n_);
    std::vector<bool> vis(n_);
    std::vector<int> prev(n_);
    std::function<bool()> dijkstra = [&]() -> bool {
      std::fill(d.begin(), d.end(), INF);
      std::fill(vis.begin(), vis.end(), false);

      std::priority_queue<std::pair<CostType, int>> q;
      d[src] = 0;
      q.push(std::make_pair(-d[src], src));

      while (!q.empty()) {
        auto [_, u] = q.top();
        q.pop();

        if (vis[u])
          continue;
        vis[u] = true;

        for (int edge_id : adjacent_[u]) {
          auto [from, to, capacity, cost] = edges_[edge_id];
          CostType new_cost = cost + h[from] - h[to];

          if (vis[to] || capacity <= 0 || d[to] <= d[from] + new_cost)
            continue;

          d[to] = d[from] + new_cost;
          prev[to] = edge_id;
          q.push(std::make_pair(-d[to], to));
        }
      }

      return d[dst] != INF;
    };

    spfa();

    CapacityType max_flow = 0;
    CostType min_cost = 0;
    while (dijkstra()) {
      CostType old_cost = min_cost;
      CapacityType augment = INF;
      for (int p = dst; p != src; p = edges_[prev[p] ^ 1].to) {
        augment = std::min(augment, edges_[prev[p]].capacity);
      }

      max_flow += augment;
      for (int p = dst; p != src; p = edges_[prev[p] ^ 1].to) {
        min_cost += edges_[prev[p]].cost * augment;
        edges_[prev[p]].capacity -= augment;
        edges_[prev[p] ^ 1].capacity += augment;
      }

      for (int i = 0; i < n_; ++i)
        h[i] += d[i];

      if (old_cost == min_cost)
        break;
    }

    return {max_flow, min_cost};
  }
};

void SolveCase(int Case) {
  int n, m;
  std::cin >> n >> m;

  std::vector<std::vector<std::pair<int, int>>> g(n);
  for (int i = 0; i < m; ++i) {
    int u, v;
    std::cin >> u >> v;
    --u, --v;
    g[u].push_back({1, v});
    g[v].push_back({1, u});
  }

  int f;
  std::cin >> f;
  std::vector<int> h(f);
  std::vector<int> count(n, 0);
  for (int i = 0; i < f; ++i) {
    std::cin >> h[i];
    --h[i];

    ++count[h[i]];
  }

  int k;
  std::cin >> k;
  std::vector<int> count_p(n, 0);
  for (int i = 0; i < k; ++i) {
    int x;
    std::cin >> x;
    --x;

    --count[h[x]];
    ++count_p[h[x]];
  }
  logd(count, count_p);

  int ans = k;
  std::vector<bool> has_car(n, true);
  for (int i = 0; i < n; ++i) {
    if (count_p[i] > 0) {
      if (count[i] == 0) {
        has_car[i] = false;
      } else {
        ans -= count_p[i];
      }
    }
  }

  auto dis = Dijkstra<int>(g, 0);
  logd(dis);

  const int INF = 0x3f3f3f3f;
  MinCostMaxFlowGraph<i64, i64> mcmf(2 * n + 1);
  int s = 2 * n;
  for (int i = 0; i < n; ++i) {
    mcmf.AddEdge(i, n + i, INF, 0);
    if (!has_car[i]) {
      logd(i, count_p[i]);
      mcmf.AddEdge(i, n + i, 1, -count_p[i]);
    }
  }
  for (int u = 0; u < n; ++u) {
    for (auto [w, v] : g[u]) {
      if (dis[u] == dis[v] + 1) {
        mcmf.AddEdge(n + u, v, INF, 0);
      }
    }
  }
  for (int i = 1; i < n; ++i) {
    if (has_car[i]) {
      logd(i);
      mcmf.AddEdge(s, i, count[i], 0);
    }
  }

  int min_cost = mcmf.EK(s, n + 0).second;
  assert(min_cost <= 0);
  ans += min_cost;
  assert(ans >= 0);
  std::cout << ans << "\n";
}

做法2

学了下 jiangly 的代码,大概就是对于每个有车的人 \(i\) ,枚举没车的人构成的集合 \(s\) ,看 \(i\) 能否顺路送所有 \(s\) 中的人回家,这个是单人的情况。多人的情况就是再跑个状压 DP 。

代码先咕咕咕。

标签:std,unique,color,++,Codeforces,int,vector,Div,826
From: https://www.cnblogs.com/zengzk/p/16786625.html

相关文章

  • 03 Quorum Queues Internals - A Deep Dive
    标题:QuorumQueuesInternals-ADeepDive原文:https://www.cloudamqp.com/blog/quorum-queues-internals-a-deep-dive.html时间:2019-04-03在本文中,我们将更详细地了解......
  • CF823div2B
    cf823div2B题目链接题目大意多组测试数据,有\(n\)个点在数轴上,他们想要集会,每个点到目标点\(y\)的时间为$$t_i+|x_i-y|$$试求所有点到\(y\)中最长时间的最小值。思路......
  • cf823div2C
    cf823div2C题目链接题目给你两个字符串\(s_1,s_2\).每次操作可以让\(s_1\)的前k个和\(s_2\)的后k个交换。询问是否可以通过多次上述操作,使得\(s_1=s_2\)。思路这种题......
  • Codeforces Round #826 (Div. 3) F // 线段树
    题目来源:CodeforcesRound#826(Div.3)F题目链接:F.Multi-ColoredSegments题意给定\(n\)条有颜色的线段(\(l_i,r_i,c_i\)),对于每条线段,求:距离该线段最近,且颜色不同的......
  • *Educational Codeforces Round 87 (Rated for Div. 2) C1. Simple Polygon Embedding
    https://codeforces.com/problemset/problem/1354/C1题目大意:给定一个数字n,表示构建出一个大小为2*n的边长的多边形;问我们可以装下这个多边形的最小的正方形的边长是......
  • CodeForces Round #826 (Div.3) 康复训练
    A模拟题,不多说。时间复杂度\(O(3)\)#include<iostream>#include<cstdio>#include<cstring>#include<map>constcharch[]={'L','M','S'};std::strings[2];s......
  • DW_div_pipe
    https://www.synopsys.com/dw/buildingblock.phphttps://max.book118.com/html/2018/0204/151848438.shtmhttps://caxapa.ru/thumbs/405687/dw_qrg.pdf无符号操作图:......
  • DIV的内容自动换行
    ​​word-break​​​:break-all和​​word-wrap​​​:break-word都是能使其容器如DIV的内容​​自动换行​​​。它们的区别就在于:1,​​​word-break​​​:break-al......
  • js div的显示与隐藏
    <divtitle="当前活动"id="workItem"href="../TiPLM/Process/FrmWork.aspx?type=WorkItem"></div><divtitle="未来任务"id="FutureTask"href="../TiPLM/Proces......
  • Codeforces Round #825 (Div. 2)D. Equal Binary Subsequences
    CodeforcesRound#825(Div.2)D.EqualBinarySubsequences题意:给定一个长度为2n的01字符串s。你可以对其中一个子序列进行向右旋转一个位置。问能否将字符串分割成......