1. 程式人生 > >topcoder srm 630 div1 (2-SAT and SCC template)

topcoder srm 630 div1 (2-SAT and SCC template)

#include <algorithm>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>

class StronglyConnectedComponentSolver {
 public:
  StronglyConnectedComponentSolver() = default;

  void Initialize(int n) { edges_.resize(n); }

  std::vector<int> Solve() {
    total_ = static_cast<int>(edges_.size());
    if (total_ == 0) {
      return {};
    }
    visited_.resize(total_, false);
    low_indices_.resize(total_, 0);
    dfs_indices_.resize(total_, 0);
    connected_component_indices_.resize(total_, 0);
    for (int i = 0; i < total_; ++i) {
      if (0 == dfs_indices_[i]) {
        Dfs(i);
      }
    }
    return connected_component_indices_;
  }

  int VertexNumber() const { return static_cast<int>(edges_.size()); }

  inline void AddEdge(int from, int to) { edges_[from].push_back(to); }

  const std::vector<int> &Tos(int u) const { return edges_[u]; }

 private:
  void Dfs(const int u) {
    low_indices_[u] = dfs_indices_[u] = ++index_;
    stack_.push(u);
    visited_[u] = true;
    for (auto v : edges_[u]) {
      if (0 == dfs_indices_[v]) {
        Dfs(v);
        low_indices_[u] = std::min(low_indices_[u], low_indices_[v]);
      } else if (visited_[v]) {
        low_indices_[u] = std::min(low_indices_[u], dfs_indices_[v]);
      }
    }
    if (dfs_indices_[u] == low_indices_[u]) {
      int v = 0;
      do {
        v = stack_.top();
        stack_.pop();
        visited_[v] = false;
        connected_component_indices_[v] = connected_component_index_;
      } while (u != v);
      ++connected_component_index_;
    }
  }

  std::vector<std::vector<int>> edges_;
  int total_ = 0;
  std::vector<bool> visited_;
  std::vector<int> low_indices_;
  std::vector<int> dfs_indices_;
  std::stack<int> stack_;
  int index_ = 0;
  int connected_component_index_ = 0;
  std::vector<int> connected_component_indices_;
};

class TwoSatisfiabilitySolver {
 public:
  void Initialize(int total_vertex_number) {
    scc_solver_.Initialize(total_vertex_number);
  }

  // If idx1 is type1, then idx2 must be type2.
  void AddConstraint(int idx1, bool type1, int idx2, bool type2) {
    int from = idx1 * 2 + (type1 ? 1 : 0);
    int to = idx2 * 2 + (type2 ? 1 : 0);
    scc_solver_.AddEdge(from, to);
  }

  void AddConflict(int idx1, bool type1, int idx2, bool type2) {
    AddConstraint(idx1, type1, idx2, !type2);
    AddConstraint(idx2, type2, idx1, !type1);
  }

  void AddLead(int idx1, bool type1, int idx2, bool type2) {
    AddConstraint(idx1, type1, idx2, type2);
    AddConstraint(idx2, !type2, idx1, !type1);
  }

  // The idx must not be type
  void SetFalse(int idx, bool type) { SetTrue(idx, !type); }

  // The idx must be type
  void SetTrue(int idx, bool type) { AddConstraint(idx, !type, idx, type); }

  bool ExistSolution() {
    if (scc_indices_.empty()) {
      scc_indices_ = scc_solver_.Solve();
      total_scc_number_ =
          *std::max_element(scc_indices_.begin(), scc_indices_.end()) + 1;
    }
    for (int i = 0; i < scc_solver_.VertexNumber() / 2; ++i) {
      if (scc_indices_[i * 2] == scc_indices_[i * 2 + 1]) {
        return false;
      }
    }
    return true;
  }

  std::vector<bool> GetOneSolution() {
    if (!ExistSolution()) {
      return {};
    }
    BuildNewGraph();
    TopSort();
    int total = scc_solver_.VertexNumber();
    std::vector<bool> result(total / 2);
    for (int e = 0; e < total / 2; ++e) {
      if (last_color_[scc_indices_[e * 2]] == 0) {
        result[e] = false;
      } else {
        result[e] = true;
      }
    }
    return std::move(result);
  }

 private:
  void BuildNewGraph() {
    new_edges_.resize(total_scc_number_);
    new_graph_node_in_degree_.resize(total_scc_number_, 0);
    int total = scc_solver_.VertexNumber();
    for (int i = 0; i < total; ++i) {
      int scc0 = scc_indices_[i];
      for (auto e : scc_solver_.Tos(i)) {
        int scc1 = scc_indices_[e];
        if (scc0 != scc1 &&
            new_edges_[scc1].find(scc0) == new_edges_[scc1].end()) {
          new_edges_[scc1].insert(scc0);
          ++new_graph_node_in_degree_[scc0];
        }
      }
    }
  }

  void TopSort() {
    std::vector<int> conflict(total_scc_number_);
    int total = scc_solver_.VertexNumber() / 2;
    for (int i = 0; i < total; ++i) {
      conflict[scc_indices_[i * 2]] = scc_indices_[i * 2 + 1];
      conflict[scc_indices_[i * 2 + 1]] = scc_indices_[i * 2];
    }
    last_color_.resize(total_scc_number_, -1);
    std::stack<int> st;
    for (int i = 0; i < total_scc_number_; ++i) {
      if (0 == new_graph_node_in_degree_[i]) {
        st.push(i);
      }
    }
    while (!st.empty()) {
      int u = st.top();
      st.pop();
      if (last_color_[u] == -1) {
        last_color_[u] = 0;
        last_color_[conflict[u]] = 1;
      }
      for (auto e : new_edges_[u]) {
        int cur = --new_graph_node_in_degree_[e];
        if (cur == 0) {
          st.push(e);
        }
      }
    }
  }

  std::vector<int> scc_indices_;
  int total_scc_number_ = 0;
  std::vector<std::unordered_set<int>> new_edges_;
  std::vector<int> new_graph_node_in_degree_;
  std::vector<int> last_color_;

  StronglyConnectedComponentSolver scc_solver_;
};

class NeverAskHerAge {
 public:
  std::vector<int> possibleSolution(int n, const std::vector<int> &id1,
                                    const std::vector<int> &id2,
                                    const std::vector<std::string> &op,
                                    const std::vector<std::string> &rl,
                                    const std::vector<int> &val) {
    solver.Initialize(n * 101 * 2);
    int m = static_cast<int>(id1.size());
    // 0: <= j
    // 1: > j
    for (int i = 1; i <= n; ++i) {
      for (int j = 0; j <= 100; ++j) {
        if (j > 0) {
          solver.AddLead(GetIndex(i, j), 1, GetIndex(i, j - 1), 1);
        }
        if (j + 1 < 100) {
          solver.AddLead(GetIndex(i, j), 0, GetIndex(i, j + 1), 0);
        }
      }
      solver.SetFalse(GetIndex(i, 0), 0);
      solver.SetFalse(GetIndex(i, 100), 1);
    }
    for (int i = 0; i < m; ++i) {
      if (rl[i] == "=") {
        Add(id1[i], id2[i], op[i][0], ">=", val[i]);
        Add(id1[i], id2[i], op[i][0], "<=", val[i]);
      } else {
        Add(id1[i], id2[i], op[i][0], rl[i], val[i]);
      }
    }
    if (!solver.ExistSolution()) {
      return {};
    }
    std::vector<int> result(n);
    auto sol = solver.GetOneSolution();
    for (int i = 0; i < n; ++i) {
      for (int j = 1; j < 101; ++j) {
        int t = GetIndex(i + 1, j);
        if (!sol[t]) {
          result[i] = j;
          break;
        }
      }
    }
    return result;
  }

 private:
  void Add(int x, int y, char op, const std::string &rl, int z) {
    if (op == '+' || op == '*') {
      if (rl[0] == '<') {
        AddMulLess(x, y, op, rl, z);
      } else {
        AddMulGreater(x, y, op, rl, z);
      }
    } else {
      if (rl[0] == '<') {
        SubDivLess(x, y, op, rl, z);
      } else {
        SubDivGreater(x, y, op, rl, z);
      }
    }
  }

  void AddMulLess(int g1, int g2, char op, const std::string &rl, int z) {
    // Assume g2 > i - 1, (i, i+1, i+2, ..., 100)
    for (int i = 1; i <= 101; ++i) {
      // If rl is '<', then 1000(i + j) < z.
      //    Here consider opposite: 1000(i + j) >= z.
      //    Get j >= ceil((z - 1000i) / 1000) = (z - 1000i + 999) / 1000
      //    So g2 >= i and g1 >= j conflicts
      // If rl is '<=', then 1000(i + j) <= z.
      //    Here consider opposite: 1000(i + j) > z.
      //    Get j >= floor((z - 1000i) / 1000) + 1 = (z - 1000i + 1000) / 1000
      //    So g2 >= i and g1 >= j conflicts
      int j = op == '+' ? Ceil(z - 1000 * i, 1000, EqualTag(rl))
                        : Ceil(z, i * 1000, EqualTag(rl));
      if (j < 1) {
        solver.SetFalse(GetIndex(g2, i - 1), 1);
      } else if (j <= 101) {
        solver.AddConflict(GetIndex(g2, i - 1), 1, GetIndex(g1, j - 1), 1);
      }
    }
  }

  void AddMulGreater(int g1, int g2, char op, const std::string &rl, int z) {
    for (int i = 0; i < 101; ++i) {
      int j = op == '+' ? Floor(z - 1000 * i, 1000, EqualTag(rl))
                        : Floor(z, i * 1000, EqualTag(rl));
      if (j >= 101) {
        solver.SetFalse(GetIndex(g2, i), 0);
      } else if (j >= 0) {
        solver.AddConflict(GetIndex(g2, i), 0, GetIndex(g1, j), 0);
      }
    }
  }

  void SubDivGreater(int g1, int g2, char op, const std::string &rl, int z) {
    for (int i = 1; i <= 101; ++i) {
      int j = op == '-' ? Floor(z + 1000 * i, 1000, EqualTag(rl))
                        : Floor(z * i, 1000, EqualTag(rl));
      if (j >= 101) {
        solver.SetFalse(GetIndex(g2, i - 1), 1);
      } else if (j >= 0) {
        solver.AddConflict(GetIndex(g2, i - 1), 1, GetIndex(g1, j), 0);
      }
    }
  }

  void SubDivLess(int g1, int g2, char op, const std::string &rl, int z) {
    for (int i = 0; i < 101; ++i) {
      int j = op == '-' ? Ceil(z + 1000 * i, 1000, EqualTag(rl))
                        : Ceil(z * i, 1000, EqualTag(rl));
      if (j < 1) {
        solver.SetFalse(GetIndex(g2, i), 0);
      } else if (j <= 101) {
        solver.AddConflict(GetIndex(g2, i), 0, GetIndex(g1, j - 1), 1);
      }
    }
  }

  bool EqualTag(const std::string &rl) { return rl.length() < 2; }

  int Ceil(int x, int y, bool tag) {
    if (x < 0) {
      return -1;
    }
    return (x + y - (tag ? 1 : 0)) / y;
  }

  int Floor(int x, int y, bool tag) {
    if (y == 0) {
      return 101;
    }
    if (x <= 0) {
      return -1;
    }
    return (x - (tag ? 0 : 1)) / y;
  }

  int GetIndex(int i, int j) { return (i - 1) * 101 + j; }

  TwoSatisfiabilitySolver solver;
};

相關推薦

topcoder srm 630 div1 (2-SAT and SCC template)

#include <algorithm> #include <stack> #include <unordered_map> #include <unordered_set> #include <vector> class Stro

topcoder srm 630 div1

problem1 link 首先計算任意兩點的距離。然後列舉選出的集合中的兩個點,判斷其他點是否可以即可。 problem2 link 假設字串為$s$,長度為$n$。那麼對於$SA$中的兩個排名$SA_{i},SA_{i+1}$來說,應該儘量使得$s[SA_{i}]=s[SA_{i+1}]$。如果這個

Topcoder SRM 603 div1題解

大於 並不是 roo swa ndb mod 我們 連接 字母 昨天剛打了一場codeforces。。。困死了。。。不過趕在睡前終於做完了~ 話說這好像是我第一次做250-500-1000的標配耶~~~ Easy(250pts): 題目大意:有一棵樹,一共n個節點,每個節點

Topcoder SRM 604 div1題解

cond 代碼 簡單 let min oge 這樣的 swe possible CTSC考完跑了過來日常TC~~~ Easy(250pts): 題目大意:有個機器人,一開始的位置在(0,0),第k個回合可以向四個方向移動3^k的距離(不能不動),問是否可以到達(x,y),數

Topcoder SRM 608 div1 題解

b+ 輸出 har 不能 include c++ point pac easy Easy(300pts): 題目大意:有n個盒子,一共有S個蘋果,每個盒子有多少個蘋果不知道,但是知道每個盒子的蘋果下限和上限。現在要至少選擇X個蘋果,問如果要保證無論如何都能獲得至少X個蘋果,

Topcoder SRM 722 Div1 600Pts DominoTiling(簡單插頭DP)

lap 就是 ont 要求 net esp $1 true mes 題意 給定一個$12*12$的矩陣,每個元素是‘.‘或‘X‘。現在要求$1*2$的骨牌鋪滿整個矩陣, ‘X‘處不能放置骨牌。求方案數。 這道題其實和 Uva11270 是差不多

Topcoder SRM 675 Div1 500Pts LimitedMemorySeries1(分塊)

tor bits fin get pre n) ted 多少 top 題意 給定一個長度不超過$5*10^{6}$的數列和不超過$100$個詢問,每次詢問這個數列第$k$小的數,返回所有詢問的和    內存限制很小,小到不能存下這個數列。(數列以種子的形式給出)   

TopCoder SRM 682 Div1 Problem 450 SuccessfulMerger (環套樹 + 分類討論)

特殊 com 新的 比較 -- ace info cpp ear 題意 給定一個$n$個點$n$條邊的無向圖,現在要把這個圖進行若幹次操作,並選擇一個點作為首都。    要求除首都外的任意兩個點$u$, $v$,從$u$走到$v$必須經過這個首都。 操

topcoder srm 738 div1 FindThePerfectTriangle(枚舉)

desc cond 問題 pub ack info win continue multiple Problem Statement You are given the ints perimeter and area. You

Topcoder SRM 563 Div1 500 SpellCards

就是 bit its () 技能 push 背包 一個 max 題意 [題目鏈接]這怎麽發鏈接啊。。。。。 有\(n\)張符卡排成一個隊列,每張符卡有兩個屬性,等級\(li\)和傷害\(di\)。 你可以做任意次操作,每次操作為以下二者之一: 把隊首的符卡移動到隊尾。 使用

topcoder srm 625 div1

problem1 link 假設第$i$種出現的次數為$n_{i}$,總個數為$m$,那麼排列數為$T=\frac{m!}{\prod_{i=1}^{26}(n_{i}!)}$ 然後計算迴文的個數,只需要考慮前一半,得到個數為$R$,那麼答案為$\frac{R}{T}$. 為了防止數字太大導致越界,可以

[題解]TopCoder SRM 625 div1 T1 PalindromePermutations

哇塞今天居然做出來了兩道TC哎~(≧▽≦)/~(好像這是什麼值得高興的事情一樣) 題目描述 給出一個字串s,問把s中的字元打亂後得到迴文串的概率是多少(|s|<=50) 分析 哎呀又是自己想出來的可開心啦 首先我們不考慮精度問題,先計算出打亂之後的所有可能字串

TopCoder SRM 568 Div1 500 EqualSums

這題可以說是花了一個多月才解決(霧 暑假的時候就很認真想過了,就是差了一步,昨天突然開竅。 emmm我真棒 我們發現題目的條件可以轉化為對於任意a[i][j]=a[i][1]+a[1][j]−a[1][1](i&gt;1,j&gt;1)a[i][

Moving By Points (topcoder SRM 738 DIV 2)

Problem Statement You are given N points. The points are numbered from 0 to N-1. Point i has coordinates (X[i], Y[i]). Note that th

topcoder srm 640 div1

problem1 link 首先使用兩個端點顏色不同的邊進行連通。答案是$n-1-m$。其中$m$是聯通分量的個數。 problem2 link 首先構造一個最小割的模型。左邊的$n_{1}$個點與源點相連,右邊的$n_{2}$個點與匯點相連。每個中間點最少有$d+1$條邊(有一條到匯點/源點的邊)。最

TopCoder SRM 666 Div1 444 SumOverPermutations

感覺是道好題~TC好多題就這樣,想半天,然後程式碼幾行就完了。 原來碰到這種排列的dp就一臉懵逼,因為狀態特別難設計,每次都感覺只會狀壓,現在終於有點get到其中的套路了。 在這題裡我們可以發現幾個事實 每個位置對答案的貢獻只和它左右兩邊是否比它早確定有關 我

TopCoder SRM 681 Div1 500 LimitedMemorySeries2

這題假得不行啊…一直感覺O(nlogn)O(nlogn)O(nlogn)是過不了的,結果TC評測機太強了啊,1e7的資料200+ms就跑過去了。。所以說要有信仰啊。。。 好的其實這題就是純暴力,複雜度證明我就直接從網上粘一個過來了。。 Let’s look a

TopCoder SRM 712 Div1 600 AverageVarianceSubtree

卡精度沒素質。。。。 今天才知道有__float128這種東西,問了一下noip不能用。。。 DescriptionDescriptionDescription 傳送門 nnn個點的樹,每個點有一個權值,任選一棵非空子樹,求其中所有點方差的期望。 Solutio

topcoder srm 575 div1

problem1 link 如果$k$是先手必勝那麼$f(k)=1$否則$f(k)=0$ 通過對前面小的數字的計算可以發現:(1)$f(2k+1)=0$,(2)$f(2^{2k+1})=0$,(3)其他情況都是1 這個可以用數學歸納法證明 problem2 link 假設字串的總長度為$n$ 首先

topcoder srm 610 div1

problem1 link  計算每個格子向上的最大高度。然後每個格子同一行前面的格子以及當前格子作為選取的矩形的最後一行,計算面積並更新答案。 problem2 link 對於兩個資料$(x_{1},y_{1}),(x_{2},y_{2})$,若先完成第一個再完成第二個,那麼一開始的值$F$需要滿足$