• AtCoder Beginner Contest 261


    咕咕咕咕。

    E - Many Operations

    题意

    给定一个值\(X\)和一个长度为\(n\)的操作序列。

    操作有3种:

    1. \(X\)替换成\(x \operatorname{and} a_i\)
    2. \(X\)替换成\(x \operatorname{or} a_i\)
    3. \(X\)替换成\(x \operatorname{xor} a_i\)

    接下来共操作\(n\)次,第\(i\)次操作时,依次执行操作序列中前\(i\)个操作。

    每次操作之后,输出当前\(X\)的值。

    其中\(1 \le n \le 2 \times {10}^5\)

    思路

    作为整数不好搞,看成二进制,然后按位处理。

    对于每一位,其实可以将多个操作压缩成一个操作,具体做法就是把真值表搞出来。

    然后离线处理一下就完事了。

    AC代码
    // Problem: E - Many Operations
    // Contest: AtCoder - AtCoder Beginner Contest 261
    // URL: https://atcoder.jp/contests/abc261/tasks/abc261_e
    // Memory Limit: 1024 MB
    // Time Limit: 2000 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);
    #define freep(p) p ? delete p, p = nullptr, void(1) : void(0)
    
    #ifdef BACKLIGHT
    #include "debug.h"
    #else
    #define logd(...) ;
    #endif
    
    using i64 = int64_t;
    using u64 = uint64_t;
    
    void solve_case(int Case);
    
    int main(int argc, char* argv[]) {
      CPPIO;
      int T = 1;
      // std::cin >> T;
      for (int t = 1; t <= T; ++t) {
        solve_case(t);
      }
      return 0;
    }
    
    void solve_case(int Case) {
      int n, X;
      std::cin >> n >> X;
    
      std::vector<int> T(n), A(n);
      for (int i = 0; i < n; ++i)
        std::cin >> T[i] >> A[i];
    
      std::vector<int> ans(n, 0);
    
      for (int j = 29; j >= 0; --j) {
        std::vector<int> x = {0, 1};
        std::vector<int> a = {0, 1};
        for (int i = 0; i < n; ++i) {
          std::vector<int> b;
          int y = ((A[i] >> j) & 1);
          if (T[i] == 1) {
            if (y == 0) {
              b = {0, 0};
            } else {
              b = {0, 1};
            }
          } else if (T[i] == 2) {
            if (y == 0) {
              b = {0, 1};
            } else {
              b = {1, 1};
            }
          } else if (T[i] == 3) {
            if (y == 0) {
              b = {0, 1};
            } else {
              b = {1, 0};
            }
          }
          a[0] = b[a[0]];
          a[1] = b[a[1]];
    
          x[0] = a[x[0]];
          x[1] = a[x[1]];
    
          int z = ((X >> j) & 1);
          int w = x[z];
          if (w)
            ans[i] |= (1 << j);
        }
      }
    
      for (int i = 0; i < n; ++i)
        std::cout << ans[i] << "\n";
    }
    
    

    F - Sorting Color Balls

    题意

    \(n\)个数排序,支持交换相邻元素这一操作。

    每个数还带一个颜色,交换同色元素不花费代价,否则花费\(1\)的代价。

    问将\(n\)个数排成非降序的最小代价。

    其中\(1\le n \le 3 \times {10}^5\)

    思路

    观察可得:对于\(x_i\),它对答案的贡献为:满足\(j < i\)\(x_j > x_i\)\(c_j \ne c_i\)\(j\)的个数。即答案为满足\(j < i\)\(x_j > x_i\)\(c_j \ne c_i\)的二元组\((i, j)\)的个数。

    为了方便计算将代价拆成两部分:满足\(j < i\)\(x_j > x_i\)的二元组\((i, j)\)的个数 减去 满足\(j < i\)\(x_j > x_i\)\(c_j = c_i\)的二元组\((i, j)\)的个数。

    现在问题就是个逆序对计数,数据结构随便搞搞。

    AC代码
    // Problem: F - Sorting Color Balls
    // Contest: AtCoder - AtCoder Beginner Contest 261
    // URL: https://atcoder.jp/contests/abc261/tasks/abc261_f
    // Memory Limit: 1024 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);
    #define freep(p) p ? delete p, p = nullptr, void(1) : void(0)
    
    #ifdef BACKLIGHT
    #include "debug.h"
    #else
    #define logd(...) ;
    #endif
    
    using i64 = int64_t;
    using u64 = uint64_t;
    
    void solve_case(int Case);
    
    int main(int argc, char* argv[]) {
      CPPIO;
      int T = 1;
      // std::cin >> T;
      for (int t = 1; t <= T; ++t) {
        solve_case(t);
      }
      return 0;
    }
    
    template <typename ValueType>
    class Treap {
     private:
      typedef int32_t size_t;
    
      struct Node {
        ValueType value;
        uint32_t priority;
        size_t size;
        Node* left;
        Node* right;
      };
      Node* root_;
      std::mt19937 rng_;
    
     private:
      Node* NewNode(ValueType value) {
        Node* p = new Node;
        p->value = value;
        p->priority = rng_();
        p->size = 1;
        p->left = p->right = nullptr;
        return p;
      }
    
      void Free(Node*& p) {
        if (p) {
          delete p;
          p = nullptr;
        }
      }
    
      size_t GetSize(Node* p) { return p ? p->size : 0; }
    
      void PushUp(Node* p) {
        if (!p)
          return;
        p->size = GetSize(p->left) + 1 + GetSize(p->right);
      }
    
      std::pair<Node*, Node*> SplitValue(Node* p, const ValueType& value) {
        if (!p)
          return {nullptr, nullptr};
    
        std::pair<Node*, Node*> result;
        if (p->value <= value) {
          auto right_result = SplitValue(p->right, value);
          p->right = right_result.first;
    
          result.first = p;
          result.second = right_result.second;
        } else {
          auto left_result = SplitValue(p->left, value);
          p->left = left_result.second;
    
          result.first = left_result.first;
          result.second = p;
        }
        PushUp(p);
    
        return result;
      }
    
      Node* Merge(Node* a, Node* b) {
        if (a == nullptr)
          return b;
        else if (b == nullptr)
          return a;
    
        Node* result;
        if (a->priority < b->priority) {
          result = a;
          a->right = Merge(a->right, b);
          PushUp(a);
        } else {
          result = b;
          b->left = Merge(a, b->left);
          PushUp(b);
        }
    
        return result;
      }
    
     public:
      Treap() : root_(nullptr), rng_(std::chrono::steady_clock::now().time_since_epoch().count()) {}
    
      ~Treap() {
        std::function<void(Node*)> dfs = [&](Node* p) -> void {
          if (!p)
            return;
          dfs(p->left);
          dfs(p->right);
          freep(p);
        };
        dfs(root_);
      }
    
      void Insert(const ValueType& value) {
        auto [a, b] = SplitValue(root_, value);
        a = Merge(a, NewNode(value));
        root_ = Merge(a, b);
      }
    
      void Delete(const ValueType& value) {
        auto [a, b] = SplitValue(root_, value);
        auto [c, d] = SplitValue(a, value - 1);
    
        assert(d);
    
        Node* temp = d;
        d = Merge(d->left, d->right);
        Free(temp);
    
        a = Merge(c, d);
        root_ = Merge(a, b);
      }
    
      size_t GetRank(const ValueType& value) {
        auto [a, b] = SplitValue(root_, value - 1);
        size_t result = GetSize(a) + 1;
        root_ = Merge(a, b);
        return result;
      }
    
      ValueType GetKth(size_t k) {
        assert(k <= GetSize(root_));
        Node* p = root_;
    
        ValueType result;
        while (p) {
          if (k <= GetSize(p->left)) {
            p = p->left;
          } else if (k == GetSize(p->left) + 1) {
            result = p->value;
            break;
          } else {
            k -= GetSize(p->left) + 1;
            p = p->right;
          }
        }
        return result;
      }
    
      ValueType GetPrev(const ValueType& value) {
        auto [a, b] = SplitValue(root_, value - 1);
    
        assert(a != nullptr);
        Node* c = a;
        while (c->right)
          c = c->right;
        ValueType result = c->value;
    
        root_ = Merge(a, b);
    
        return result;
      }
    
      ValueType GetNext(const ValueType& value) {
        auto [a, b] = SplitValue(root_, value);
    
        assert(b != nullptr);
        Node* c = b;
        while (c->left)
          c = c->left;
        ValueType result = c->value;
    
        root_ = Merge(a, b);
    
        return result;
      }
    
      size_t Get(const ValueType& value) {
        auto [a, b] = SplitValue(root_, value);
        size_t result = GetSize(b);
        root_ = Merge(a, b);
        return result;
      }
    };
    using Tp = Treap<int>;
    
    std::mt19937 rng(114514);
    int rnd(int l, int r) {
      return l + rng() % (r - l + 1);
    }
    
    void solve_case(int Case) {
      int n;
      std::cin >> n;
    
      std::vector<int> c(n), x(n);
      for (int i = 0; i < n; ++i) {
        std::cin >> c[i];
        --c[i];
      }
      for (int i = 0; i < n; ++i) {
        std::cin >> x[i];
      }
    
      std::vector<std::vector<int>> d(n);
      for (int i = 0; i < n; ++i) {
        d[c[i]].push_back(x[i]);
      }
    
      i64 ans = 0;
      Tp t;
      for (int i = 0; i < n; ++i) {
        ans += t.Get(x[i]);
        t.Insert(x[i]);
      }
    
      for (int i = 0; i < n; ++i) {
        Tp tp;
        for (int v : d[i]) {
          ans -= tp.Get(v);
          tp.Insert(v);
        }
      }
    
      std::cout << ans << "\n";
    }
    
    
    

    G - Replace

    题意

    给定初始串\(s\)和目标串\(t\),以及\(k\)个转移\((c_i, a_i)\),表示可以将\(s_i\)中的一个字符\(c_i\)替换成\(a_i\)

    问将\(s\)变成\(t\)的最小转移次数。

    其中\(1 \le |s|, |t|, k, |a_i| \le 50\)

    思路

    动态规划。

    \(s[l; r]\)表示\(s_{l}s_{l+1}\dots s_{r}\)\(f(l, r, c)\)表示从字符\(c\)变成\(t[l; r - 1]\)的最小操作次数,\(g(l, r, i, j)\)表示从\(a_i[0; j - 1]\)变成\(t[l; r - 1]\)的最小操作次数。

    为方便讨论,记\(a_{k}\)\(s\)。易得答案为\(g_{0, |t|, k, |s|}\)

    \(f\)的转移:

    • \(t[l; r]\)匹配了完整的\(a_i\)时,那么就可以从\(c_i\)转移到\(a_i\)再转移到\(t[l; r]\)。即\(g(l, r, i, |a_i|) + 1\)可以用来更新\(f(l, r, c_i)\)
    • \(|a_i| = 1\)时,则可以从\(c_i\)转移到\(a_i[0]\),即\(f(l, r, x) + dis(x, y)\)可以用来更新\(f(l, r, y)\),其中\(x, y\)可以是任意字符,\(dis(x, y)\)表示从\(x\)转移到\(y\)的代价。这里的\(dis\)可以搞个最短路求。

    \(g\)的转移:

    • \(t[l; r]\)匹配了\(a_i[0; j - 1]\)时,在此基础上可以拓展\(a_i[j]\)从而匹配\(t[l; r^\prime], r^\prime > r\)。即对于\(l \le m < r\)\(g(l, m, i, j) + f(m, r, a_i[j])\)可以用来更新\(g(l, r, i, j + 1)\)
    • \(f(l, r, a_i[0])\)可以用来更新\(g(l, r, i, 1)\)

    根据转移的特点,升序枚举\(r\)套降序枚举\(l\),即可保证求解某个问题时,依赖的子问题已经全部解决,然后就可以愉快的转移了。

    AC代码
    // Problem: G - Replace
    // Contest: AtCoder - AtCoder Beginner Contest 261
    // URL: https://atcoder.jp/contests/abc261/tasks/abc261_g
    // Memory Limit: 1024 MB
    // Time Limit: 2000 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);
    #define freep(p) p ? delete p, p = nullptr, void(1) : void(0)
    
    #ifdef BACKLIGHT
    #include "debug.h"
    #else
    #define logd(...) ;
    #endif
    
    using i64 = int64_t;
    using u64 = uint64_t;
    
    void solve_case(int Case);
    
    int main(int argc, char* argv[]) {
      CPPIO;
      int T = 1;
      // std::cin >> T;
      for (int t = 1; t <= T; ++t) {
        solve_case(t);
      }
      return 0;
    }
    
    template <typename T>
    std::vector<T> Vector(size_t n, T init) {
      return std::vector<T>(n, init);
    }
    
    template <typename T>
    std::vector<std::vector<T>> Vector(size_t n, size_t m, T init) {
      using value_type = decltype(Vector<T>(0, T()));
      return std::vector<value_type>(n, Vector<T>(m, init));
    }
    
    template <typename T>
    std::vector<std::vector<std::vector<T>>> Vector(size_t n, size_t m, size_t k, T init) {
      using value_type = decltype(Vector<T>(0, 0, T()));
      return std::vector<value_type>(n, Vector<T>(m, k, init));
    }
    
    template <typename T>
    std::vector<std::vector<std::vector<std::vector<T>>>> Vector(size_t n,
                                                                 size_t m,
                                                                 size_t k,
                                                                 size_t l,
                                                                 T init) {
      using value_type = decltype(Vector<T>(0, 0, 0, T()));
      return std::vector<value_type>(n, Vector<T>(m, k, l, init));
    }
    
    const int INF = 0x3f3f3f3f;
    
    void solve_case(int Case) {
      std::string S, T;
      std::cin >> S >> T;
      int N = S.size(), M = T.size();
    
      int K;
      std::cin >> K;
      std::string C(K + 1, '?');
      std::vector<std::string> A(K + 1);
      for (int i = 0; i < K; ++i) {
        std::cin >> C[i] >> A[i];
      }
      C[K] = '*';
      A[K] = S;
    
      auto trans = Vector<int>(26, 26, INF);
      for (int i = 0; i < K; ++i) {
        if (static_cast<int>(A[i].size()) == 1) {
          int u = C[i] - 'a';
          int v = A[i][0] - 'a';
          trans[v][u] = 1;
        }
      }
      for (int i = 0; i < 26; ++i)
        trans[i][i] = 0;
      for (int k = 0; k < 26; ++k) {
        for (int i = 0; i < 26; ++i) {
          for (int j = 0; j < 26; ++j) {
            trans[i][j] = std::min(trans[i][j], trans[i][k] + trans[k][j]);
          }
        }
      }
    
      auto f = Vector<int>(M + 1, M + 1, 26, INF);
      auto g = Vector<int>(M + 1, M + 1, K + 1, 51, INF);
    
      // DP
      // init.
      for (int i = 0; i < M; ++i) {
        f[i][i + 1][T[i] - 'a'] = 0;
      }
      for (int i = 0; i <= M; ++i) {
        for (int k = 0; k <= K; ++k) {
          g[i][i][k][0] = 0;
        }
      }
    
      // trans.
      for (int r = 1; r <= M; ++r) {
        for (int l = r - 1; l >= 0; --l) {
          for (int i = 0; i <= K; ++i) {
            int L = static_cast<int>(A[i].size());
            for (int j = 0; j < L; ++j) {
              for (int m = l; m < r; ++m) {
                g[l][r][i][j + 1] = std::min(g[l][r][i][j + 1], g[l][m][i][j] + f[m][r][A[i][j] - 'a']);
              }
            }
            if (i != K) {
              f[l][r][C[i] - 'a'] = std::min(f[l][r][C[i] - 'a'], g[l][r][i][L] + 1);
            }
          }
    
          for (int u = 0; u < 26; ++u) {
            for (int v = 0; v < 26; ++v) {
              f[l][r][u] = std::min(f[l][r][u], f[l][r][v] + trans[v][u]);
            }
          }
    
          for (int i = 0; i <= K; ++i) {
            g[l][r][i][1] = std::min(g[l][r][i][1], f[l][r][A[i][0] - 'a']);
          }
        }
      }
    
      int ans = g[0][M][K][N];
      if (ans == INF)
        ans = -1;
      std::cout << ans << "\n";
    }
    
    

    Ex - Game on Graph

    题意

    给一个\(n\)个点\(m\)条边的有向图,边带权。

    两个人完游戏,点\(S\)上有一个棋子。假设某个时刻棋子位于点\(u\),则此时的操作者可以选择点\(v\)并将棋子移动到点\(v\),要求边\(u \to v\)存在,且代价为边权。无法移动棋子时游戏结束。

    可能存在游戏无法结束的情况,先手想要避免这种情况,后手想要造成这种情况,此外,先手想要最小化代价,后手想要最大化代价,两个人都以最优策略玩游戏。

    问游戏是否可以结束,如果可以的话结束时代价是多少。

    其中\(1 \le n \le 2 \times {10}^5, 0 \le m \le 2 \times {10}^5\)

    思路

    建议先做ABC209E。

    这个题目就是在ABC209E的基础上,还要求代价最小或者最大。可以搞个优先队列优先考虑代价小的点,然后在后手玩家操作时手动选择代价大的后继。

    AC代码
    // Problem: Ex - Game on Graph
    // Contest: AtCoder - AtCoder Beginner Contest 261
    // URL: https://atcoder.jp/contests/abc261/tasks/abc261_h
    // Memory Limit: 1024 MB
    // Time Limit: 2000 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);
    #define freep(p) p ? delete p, p = nullptr, void(1) : void(0)
    
    #ifdef BACKLIGHT
    #include "debug.h"
    #else
    #define logd(...) ;
    #endif
    
    using i64 = int64_t;
    using u64 = uint64_t;
    
    void solve_case(int Case);
    
    int main(int argc, char* argv[]) {
      CPPIO;
      int T = 1;
      // std::cin >> T;
      for (int t = 1; t <= T; ++t) {
        solve_case(t);
      }
      return 0;
    }
    
    struct Edge {
      int v, w;
    };
    
    void solve_case(int Case) {
      int n, m, S;
      std::cin >> n >> m >> S;
      --S;
    
      std::vector<std::vector<Edge>> g(n);
      std::vector<int> deg(n, 0);
      for (int i = 0; i < m; ++i) {
        int u, v, w;
        std::cin >> u >> v >> w;
        --u, --v;
        g[v].push_back((Edge){u, w});
        ++deg[u];
      }
    
      std::vector<std::vector<i64>> dp(n, std::vector<i64>(2, -1));
      std::vector<i64> mx(n, 0);
      std::priority_queue<std::tuple<i64, int, int>, std::vector<std::tuple<i64, int, int>>,
                          std::greater<std::tuple<i64, int, int>>>
          q;
      for (int i = 0; i < n; ++i) {
        if (deg[i] == 0) {
          q.push(std::make_tuple(INT64_C(0), i, 0));
          q.push(std::make_tuple(INT64_C(0), i, 1));
        }
      }
      while (!q.empty()) {
        auto [x, u, t] = q.top();
        q.pop();
    
        if (dp[u][t] != -1)
          continue;
        dp[u][t] = x;
    
        if (t == 0) {
          for (auto [v, w] : g[u]) {
            mx[v] = std::max(mx[v], x + w);
            --deg[v];
            if (deg[v] == 0) {
              q.push(std::make_tuple(mx[v], v, 1));
            }
          }
        } else {
          for (auto [v, w] : g[u]) {
            q.push(std::make_tuple(x + w, v, 0));
          }
        }
      }
    
      if (dp[S][0] == -1)
        std::cout << "INFINITY\n";
      else
        std::cout << dp[S][0] << std::endl;
    }
    
    
  • 相关阅读:
    Visual C# 2008+SQL Server 2005 数据库与网络开发 6.3 创建Crystal Reports应用程序
    Visual C# 2008+SQL Server 2005 数据库与网络开发6.1.2 报表服务组件
    Visual C# 2008+SQL Server 2005 数据库与网络开发第7章 使用数据库
    Visual C# 2008+SQL Server 2005 数据库与网络开发7.1.1 EMIS数据库
    Visual C# 2008+SQL Server 2005 数据库与网络开发6.2.1 创建报表应用程序
    Visual C# 2008+SQL Server 2005 数据库与网络开发 6.2 报表应用程序
    Visual C# 2008+SQL Server 2005 数据库与网络开发 6.4 小结
    Visual C# 2008+SQL Server 2005 数据库与网络开发7.1.2 连接数据库
    Visual C# 2008+SQL Server 2005 数据库与网络开发6.1.3 报表服务的安装
    【C#笔记】关于 Random类
  • 原文地址:https://www.cnblogs.com/zengzk/p/16514927.html
Copyright © 2020-2023  润新知