topcoder srm 712 div1

problem1 link

将$a_{0},a_{1},...,a_{n-1}$看做$a_{0}x^{0}+a_{1}x^{1}+...+a_{n-1}x^{n-1}$。那么第一种操作相当于乘以$1+x$模$x^{n}-1$,第二种操作相当于乘以$1+x^{n-1}$模$x^{n}-1$。所以操作的顺序无关。所以只需要枚举两种操作各用了多少次即可

problem2 link

对于$m$个数字$x_{1},x_{2},..,x_{m}$来说,设$a=\frac{\sum_{i=1}^{m}x_{i}}{m}$,那么$\frac{1}{m}\sum_{i=1}^{m}(x_{i}-a)^{2}=\frac{1}{m}\left (\sum_{i=1}^{m}x_{i}^{2}-\frac{\left (\sum_{i=1}^{m}x_{i}  \right )^{2}}{m^{2}}  \right )$

所以,对于子树$T$,可以计算包含子树树根的大小为$m$的连通块有多少个,同时记录所有情况的$s_{1}=\sum_{i=1}^{m}x_{i}^{2},s_{2}=\left (\sum_{i=1}^{m}x_{i}  \right )^{2}$之和。这样就是一个树上的动态规划。

problem3 link

 首先,将所有的限制按照最近公共祖先分配到每个对应的结点上。那么现在就是每个子树有一些限制。

首先,分配结点以满足左右子树的限制。对于当前结点,枚举当前结点映射为最后的哪一个结点。

这时候对于限制,可以确定每个限制的$(x,y)$,$x$或者$y$:(1)一定在左侧;(2)一定在右侧;(3)都可以;(4)不是一定在左侧或者右侧但是$x$和$y$不能在一侧。第三类情况最后可以随意分配,比较简单。第四种情况暴力枚举$x$在左侧还是右侧。这样就可以确定所有的结点。

 

code for problem1

#include <algorithm>
#include <string>
#include <vector>

class LR {
 public:
  std::string construct(const std::vector<long long> &s,
                        const std::vector<long long> &t) {
    if (s == t) {
      return "";
    }
    int n = static_cast<int>(s.size());
    long long x0 = std::accumulate(s.begin(), s.end(), 0ll);
    long long x1 = std::accumulate(t.begin(), t.end(), 0ll);
    if (x0 == 0) {
      return "No solution";
    }
    int k = 0;
    while (x0 < x1) {
      ++k;
      x0 <<= 1;
    }
    if (x0 != x1) {
      return "No solution";
    }
    auto Check = [&](std::vector<long long> s, int x, int y) {
      for (int i = 0; i < x; ++i) {
        long long t = s[n - 1];
        for (int i = n - 1; i > 0; --i) {
          s[i] += s[i - 1];
        }
        s[0] += t;
      }
      for (int i = 0; i < y; ++i) {
        long long t = s[0];
        for (int i = 0; i < n - 1; ++i) {
          s[i] += s[i + 1];
        }
        s[n - 1] += t;
      }
      return s == t;
    };
    for (int i = 0; i <= k; ++i) {
      if (Check(s, i, k - i)) {
        return std::string(i, 'L') + std::string(k - i, 'R');
      }
    }
    return "No solution";
  }
};

code for problem2

#include <vector>

using BigDouble = __float128;

class AverageVarianceSubtree {
  struct Node {
    BigDouble s1 = 0.0;
    BigDouble s2 = 0.0;
    BigDouble s3 = 0.0;
    BigDouble number = 0;

    void Reset() {
      s1 = s2 = s3 = 0.0;
      number = 0;
    }

    Node Merge(const Node &other) {
      Node result;
      result.s1 = s1 * other.number + other.s1 * number;
      result.s2 = s2 * other.number + other.s2 * number + 2 * s3 * other.s3;
      result.s3 = s3 * other.number + other.s3 * number;
      result.number = number * other.number;
      return std::move(result);
    }

    void Add(const Node &other) {
      s1 += other.s1;
      s2 += other.s2;
      s3 += other.s3;
      number += other.number;
    }
  };

 public:
  double average(const std::vector<int> &p, const std::vector<int> &weight) {
    n = static_cast<int>(p.size()) + 1;
    tree.resize(n);
    for (int i = 0; i < n - 1; ++i) {
      tree[i + 1].push_back(p[i]);
      tree[p[i]].push_back(i + 1);
    }
    this->weights = weight;
    dp.resize(n);
    for (int i = 0; i < n; ++i) {
      dp[i].resize(n + 1);
    }
    BigDouble sum = 0;
    BigDouble total = 0;
    Dfs(0, -1);
    for (int root = 0; root < n; ++root) {
      for (int i = 1; i <= n; ++i) {
        sum += (dp[root][i].s1 * i - dp[root][i].s2) / i / i;
        total += dp[root][i].number;
      }
    }
    return static_cast<double>(sum / total);
  }

 private:
  void Dfs(int u, int prev) {
    long long w1 = weights[u];
    long long w2 = w1 * w1;
    dp[u][0].number = 1;
    for (auto v : tree[u]) {
      if (v == prev) {
        continue;
      }
      Dfs(v, u);
      std::vector<Node> f(n + 1);
      for (int i = 0; i <= n; ++i) {
        for (int j = 0; j <= n; ++j) {
          if (i + j <= n) {
            f[i + j].Add(dp[v][i].Merge(dp[u][j]));
          }
        }
      }
      dp[u] = std::move(f);
    }

    for (int i = n - 1; i >= 0; --i) {
      dp[u][i + 1].s1 = dp[u][i].s1 + dp[u][i].number * w2;
      dp[u][i + 1].s2 =
          dp[u][i].s2 + dp[u][i].number * w2 + 2 * w1 * dp[u][i].s3;
      dp[u][i + 1].s3 = dp[u][i].s3 + dp[u][i].number * w1;
      dp[u][i + 1].number = dp[u][i].number;
    }
  }

  std::vector<std::vector<int>> tree;
  std::vector<int> weights;
  std::vector<std::vector<Node>> dp;
  int n = 0;
};

code for problem3

#include <unordered_set>
#include <vector>

class BinaryTreeAndPermutation {
  struct Node {
    long long contain_ps = 0;
    long long contain = 0;
    long long used = 0;
    int left = -1;
    int right = -1;
    int total = 0;
    std::vector<std::pair<int, int>> constrains;
    int n = 0;

    void Used(int t) { used |= 1ll << t; }

    void AddConstrain(int x, int y) {
      for (const auto &e : constrains) {
        if ((e.first == x && e.second == y) ||
            (e.first == y && e.second == x)) {
          return;
        }
      }
      constrains.emplace_back(x, y);
    }

    size_t UnUsedNodeNumber() const {
      size_t num = 0;
      for (int i = 0; i < n; ++i) {
        if ((contain & (1ll << i)) != 0 && (used & (1ll << i)) == 0) {
          ++num;
        }
      }
      return num;
    }

    int UnUsedNode() const {
      for (int i = 0; i < n; ++i) {
        if ((contain & (1ll << i)) != 0 && (used & (1ll << i)) == 0) {
          return i;
        }
      }
      return -1;
    }

    long long AllPs() const {
      long long m = 0;
      for (const auto &x : constrains) {
        m |= 1ll << x.first;
        m |= 1ll << x.second;
      }
      return m;
    }

    bool Has(int x) const { return (contain_ps & (1ll << x)) != 0; }
  };

 public:
  std::vector<int> findPermutation(const std::vector<int> &lef,
                                   const std::vector<int> &rig,
                                   const std::vector<int> &a,
                                   const std::vector<int> &b,
                                   const std::vector<int> &c) {
    n = static_cast<int>(lef.size());
    tree.resize(n);
    for (int i = 0; i < n; ++i) {
      tree[i].left = lef[i];
      tree[i].right = rig[i];
      tree[i].n = n;
    }
    for (size_t i = 0; i < a.size(); ++i) {
      tree[c[i]].AddConstrain(a[i], b[i]);
    }
    result.resize(n, -1);
    if (!Dfs(0)) {
      return {};
    }
    for (int i = 0; i < n; ++i) {
      if (result[i] == -1) {
        result[i] = tree[0].UnUsedNode();
        tree[0].Used(result[i]);
      }
    }

    return result;
  }

 private:
  bool Split(
      const std::vector<std::pair<int, int>> &undecided,
      std::vector<std::pair<std::unordered_set<int>, std::unordered_set<int>>>
          *result) {
    int m = static_cast<int>(undecided.size());
    std::vector<bool> visited(m);
    for (int i = 0; i < m; ++i) {
      if (!visited[i]) {
        result->emplace_back();
        auto &curr = result->back();
        curr.first.insert(undecided[i].first);
        curr.second.insert(undecided[i].second);
        while (true) {
          bool updated = false;
          for (int j = i + 1; j < m; ++j) {
            if (!visited[j]) {
              int x = undecided[j].first;
              int y = undecided[j].second;
              if ((curr.first.count(x) > 0 && curr.first.count(y)) > 0 ||
                  (curr.second.count(x) > 0 && curr.second.count(y) > 0)) {
                return false;
              }
              if (curr.first.count(x) > 0 || curr.second.count(y) > 0) {
                curr.first.insert(x);
                curr.second.insert(y);
                updated = true;
                visited[j] = true;
              } else if (curr.first.count(y) > 0 || curr.second.count(x) > 0) {
                curr.first.insert(y);
                curr.second.insert(x);
                updated = true;
                visited[j] = true;
              }
            }
          }
          if (!updated) {
            break;
          }
        }
      }
    }
    return true;
  }

  bool Check(int root, int root_p) {
    Node &node = tree[root];
    Node &left = tree[node.left];
    Node &right = tree[node.right];
    if (root_p != -1 && ((left.contain_ps & (1ll << root_p)) != 0 ||
                         (right.contain_ps & (1ll << root_p)) != 0)) {
      return false;
    }

    std::unordered_set<int> must_left;
    std::unordered_set<int> must_right;
    std::unordered_set<int> root_pair;
    std::vector<std::pair<int, int>> undecided;
    for (const auto &x : node.constrains) {
      if (x.first == root_p && x.second == root_p) {
        continue;
      }
      if (x.first == root_p) {
        if (!left.Has(x.second) && !right.Has(x.second)) {
          root_pair.insert(x.second);
        }
      } else if (x.second == root_p) {
        if (!left.Has(x.first) && !right.Has(x.first)) {
          root_pair.insert(x.first);
        }
      } else if (left.Has(x.first) || right.Has(x.second)) {
        if (!left.Has(x.first)) {
          must_left.insert(x.first);
        }
        if (!right.Has(x.second)) {
          must_right.insert(x.second);
        }
      } else if (left.Has(x.second) || right.Has(x.first)) {
        if (!left.Has(x.second)) {
          must_left.insert(x.second);
        }
        if (!right.Has(x.first)) {
          must_right.insert(x.first);
        }
      } else {
        undecided.push_back(x);
      }
    }
    for (auto x : must_left) {
      if (must_right.count(x) > 0) {
        return false;
      }
    }
    for (auto x : must_right) {
      if (must_left.count(x) > 0) {
        return false;
      }
    }
    for (const auto &e : undecided) {
      if (root_pair.count(e.first) > 0) {
        root_pair.erase(e.first);
      }
      if (root_pair.count(e.second) > 0) {
        root_pair.erase(e.second);
      }
    }
    while (true) {
      bool deleted = false;
      for (size_t i = 0; i < undecided.size(); ++i) {
        int x = undecided[i].first;
        int y = undecided[i].second;
        if ((must_left.count(x) > 0 && must_left.count(y) > 0) ||
            (must_right.count(x) > 0 && must_right.count(y) > 0)) {
          return false;
        }
        if ((must_left.count(x) > 0 && must_right.count(x) > 0) ||
            (must_left.count(y) > 0 && must_right.count(y) > 0)) {
          return false;
        }
        if (must_left.count(x) > 0 || must_right.count(y) > 0) {
          must_left.insert(x);
          must_right.insert(y);
          deleted = true;
          undecided.erase(undecided.begin() + i);
          break;
        } else if (must_left.count(y) > 0 || must_right.count(x) > 0) {
          must_left.insert(y);
          must_right.insert(x);
          deleted = true;
          undecided.erase(undecided.begin() + i);
          break;
        }
      }
      if (!deleted) {
        break;
      }
    }

    for (int x : must_left) {
      root_pair.erase(x);
    }
    for (int x : must_right) {
      root_pair.erase(x);
    }
    if (tree[node.left].UnUsedNodeNumber() < must_left.size() ||
        tree[node.right].UnUsedNodeNumber() < must_right.size()) {
      return false;
    }
    std::vector<std::pair<std::unordered_set<int>, std::unordered_set<int>>>
        splits;
    if (!Split(undecided, &splits)) {
      return false;
    }

    size_t total = must_left.size() + must_right.size() + root_pair.size();
    for (const auto &e : splits) {
      total += e.first.size() + e.second.size();
    }
    if (static_cast<int>(total) > tree[root].total) {
      return false;
    }
    int m = static_cast<int>(splits.size());
    bool valid_assign = false;
    for (int i = 0; i < (1 << m); ++i) {
      size_t left_num = 0;
      size_t right_num = 0;
      for (int j = 0; j < m; ++j) {
        size_t num1 = splits[j].first.size();
        size_t num2 = splits[j].second.size();
        if ((i & (1 << j)) == 0) {
          left_num += num1;
          right_num += num2;
        } else {
          left_num += num2;
          right_num += num1;
        }
      }
      if (left_num + must_left.size() <= tree[node.left].UnUsedNodeNumber() &&
          right_num + must_right.size() <=
              tree[node.right].UnUsedNodeNumber()) {
        valid_assign = true;
        for (int j = 0; j < m; ++j) {
          if ((i & (1 << j)) == 0) {
            must_left.insert(splits[j].first.begin(), splits[j].first.end());
            must_right.insert(splits[j].second.begin(), splits[j].second.end());
          } else {
            must_right.insert(splits[j].first.begin(), splits[j].first.end());
            must_left.insert(splits[j].second.begin(), splits[j].second.end());
          }
        }
        break;
      }
    }

    if (!valid_assign) {
      return false;
    }
    for (auto x : root_pair) {
      if (tree[node.left].UnUsedNodeNumber() > must_left.size()) {
        must_left.insert(x);
      } else {
        must_right.insert(x);
      }
    }
    for (auto x : must_left) {
      int t = tree[node.left].UnUsedNode();
      result[x] = t;
      tree[node.left].Used(t);
    }
    for (auto x : must_right) {
      int t = tree[node.right].UnUsedNode();
      result[x] = t;
      tree[node.right].Used(t);
    }
    node.used = tree[node.left].used | tree[node.right].used;
    if (root_p != -1) {
      result[root_p] = root;
      node.used |= 1ll << root;
    }
    node.contain =
        tree[node.left].contain | tree[node.right].contain | 1ll << root;
    return true;
  }

  bool Dfs(int root) {
    Node &node = tree[root];
    if (node.left == -1) {
      node.contain = 1ll << root;
      node.total = 1;
      if (!node.constrains.empty()) {
        int p = node.constrains.front().first;
        for (const auto &x : node.constrains) {
          if (p != x.first || p != x.second) {
            return false;
          }
        }
        node.contain_ps = 1ll << p;
        node.used = 1ll << root;
        result[p] = root;
      }
      return true;
    }
    if (!Dfs(node.left) || !Dfs(node.right)) {
      return false;
    }
    long long cur_ps = node.AllPs();
    long long left_ps = tree[node.left].contain_ps;
    long long right_ps = tree[node.right].contain_ps;

    node.contain_ps = cur_ps | left_ps | right_ps;
    node.total = 1 + tree[node.left].total + tree[node.right].total;

    Node &left = tree[node.left];
    Node &right = tree[node.right];

    int root_p = -1;
    for (const auto &x : node.constrains) {
      if ((left.Has(x.first) && left.Has(x.second)) ||
          (right.Has(x.first) && right.Has(x.second)) ||
          (left.Has(x.first) && right.Has(x.first)) ||
          (left.Has(x.second) && right.Has(x.second))) {
        return false;
      }
      if (x.first == x.second) {
        if (root_p != -1 && root_p != x.first) {
          return false;
        }
        root_p = x.first;
      }
    }

    if (root_p != -1) {
      return Check(root, root_p);
    } else {
      if (Check(root, -1)) {
        return true;
      }
      for (int i = 0; i < n; ++i) {
        if ((cur_ps & (1ll << i)) != 0 && Check(root, i)) {
          return true;
        }
      }
      return false;
    }
  }

  std::vector<int> result;
  std::vector<Node> tree;
  int n = 0;
};
posted @ 2017-05-05 22:03  朝拜明天19891101  阅读(356)  评论(0编辑  收藏  举报