topcoder srm 679 div1
problem1 link
$f[u][0],f[u][1]$表示$u$节点表示的子树去掉和不去掉节点$u$的最大权值。
problem2 link
首先预处理计算任意三个蓝点组成的三角形中的蓝点个数以及是否包含红点。凸包可以分割成三角形。首先初始化凸包的三个顶点为$x,y,z$(假设$x,y,z$是逆时针),然后每次增加一个新的点进来,设最后加入凸包的两个点为$p_{1},p_{2}$,新加入的点为$q$,那么$q$需要满足的条件为:
(1)三角形$x,p_{2},q$中没有红点;
(2)$q$在射线$x,p_{2}$的左侧;
(3)$q$在射线$p_{1},p_{2}$的左侧;
(4)$q$在射线$x,y$的左侧.
这样进行动态规划即可。
problem3 link
令$s(i,j)=\sum_{0\leq k <m}count(i,k)[isGood_{j+k}]$,表示某个$bag$中取出的数字为$j$时,$bag$$i$中那些可以与$j$组成$good$的数字的方案数。
那么答案为$answer=\sum_{0\leq t<n}\sum_{0\leq j<m}count(t,j)\left (\sum_{t<i<n}s(i,j) \right )$
code for problem1
#include <algorithm> #include <stack> #include <vector> class FiringEmployees { public: int fire(const std::vector<int> &manager, const std::vector<int> &salary, const std::vector<int> &productivity) { int n = static_cast<int>(manager.size()); std::vector<std::vector<int>> g(n + 1); std::vector<int> a(n + 1); std::vector<int> f0(n + 1); std::vector<int> f1(n + 1); for (int i = 0; i < n; ++i) { g[manager[i]].push_back(i + 1); } for (int i = 1; i <= n; ++i) { f1[i] = a[i] = productivity[i - 1] - salary[i - 1]; } std::stack<std::pair<int, int>> st; st.push({0, 0}); while (!st.empty()) { int u = st.top().first; int tag = st.top().second; st.pop(); if (tag == 1) { for (auto son : g[u]) { f1[u] += std::max(f0[son], f1[son]); } } else { st.push({u, 1}); for (auto son : g[u]) { st.push({son, 0}); } } } return f1[0]; } };
code for problem2
#include <algorithm> #include <cstring> #include <queue> #include <vector> namespace geometry { struct Point { double x, y; Point(double x = 0.0, double y = 0.0) : x(x), y(y) {} Point operator+(const Point &a) const { return Point(x + a.x, y + a.y); } Point operator-(const Point &a) const { return Point(x - a.x, y - a.y); } double operator*(const Point &a) const { return x * a.y - y * a.x; } double operator^(const Point &a) const { return x * a.x + y * a.y; } Point operator*(double t) const { return Point(x * t, y * t); } Point operator/(double t) const { return Point(x / t, y / t); } }; int SGN(double x) { constexpr double kEpslion = 1e-12; if (x > kEpslion) { return 1; } if (x < -kEpslion) { return -1; } return 0; } double Cross(const Point &a, const Point &b, const Point &p) { return (b - a) * (p - a); } bool Left(const Point &a, const Point &b, const Point &p) { return ((b - a) * (p - a)) > 0; } double Area(const Point &a, const Point &b, const Point &c) { return std::fabs(Cross(a, b, c)) * 0.5; } bool Inside(const Point &a, const Point &b, const Point &c, const Point &d) { double s1 = Area(a, b, c); double s2 = Area(a, b, d) + Area(a, c, d) + Area(b, c, d); return SGN(s1 - s2) == 0; } } // namespace geometry const int N = 50; bool tag[N][N][N]; int f[N][N][N]; bool inque[N][N][N]; int g[N][N][N]; class RedAndBluePoints { public: int find(const std::vector<int> &blueX, const std::vector<int> &blueY, const std::vector<int> &redX, const std::vector<int> &redY) { int n = static_cast<int>(blueX.size()); if (n <= 2) { return n; } std::vector<geometry::Point> p(n); for (int i = 0; i < n; ++i) { p[i] = geometry::Point(blueX[i], blueY[i]); } int m = static_cast<int>(redX.size()); std::vector<geometry::Point> q(m); for (int i = 0; i < m; ++i) { q[i] = geometry::Point(redX[i], redY[i]); } auto Cal = [&](const geometry::Point &a, const geometry::Point &b, const geometry::Point &c) { for (int i = 0; i < m; ++i) { if (geometry::Inside(a, b, c, q[i])) { return true; } } return false; }; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { for (int k = 0; k < n; ++k) { if (i != j && i != k && j != k) { tag[i][j][k] = Cal(p[i], p[j], p[k]); for (int t = 0; t < n; ++t) { if (t != i && t != j && t != k && geometry::Inside(p[i], p[j], p[k], p[t])) { ++g[i][j][k]; } } } } } } int result = 2; for (int i = 0; i < n; ++i) { result = std::max(result, Get(i, p)); } return result; } private: int Get(int x, const std::vector<geometry::Point> &p) { int n = static_cast<int>(p.size()); struct Node { int i, j, t, cnt; Node() = default; Node(int i, int j, int t, int cnt) : i(i), j(j), t(t), cnt(cnt) {} }; memset(f, 0, sizeof(f)); memset(inque, 0, sizeof(inque)); std::queue<Node> que; int result = 0; for (int i = 0; i < n; ++i) { for (int j = 0; j < n; ++j) { if (i != x && i != j && j != x && !tag[x][i][j] && geometry::Left(p[x], p[i], p[j])) { f[i][i][j] = 3 + g[x][i][j]; result = std::max(result, f[i][i][j]); inque[i][i][j] = true; que.push(Node(i, j, i, f[i][i][j])); } } } while (!que.empty()) { Node node = que.front(); que.pop(); int y = node.t; int p1 = node.i; int p2 = node.j; inque[y][p1][p2] = false; for (int q = 0; q < n; ++q) { if (q == x || q == y || q == p1 || q == p2 || tag[x][p2][q]) { continue; } if (geometry::Left(p[p1], p[p2], p[q]) && geometry::Left(p[x], p[p2], p[q]) && geometry::Left(p[x], p[y], p[q])) { int sum = node.cnt + 1 + g[p2][q][x]; if (f[y][p2][q] < sum) { f[y][p2][q] = sum; result = std::max(result, sum); if (!inque[y][p2][q]) { inque[y][p2][q] = true; que.push(Node(p2, q, y, sum)); } } } } } return result; } };
code for problem3
#include <string> #include <vector> class BagAndCards { public: int getHash(int n, int m, int x, int a, int b, int c, const std::string &isGood) { constexpr int kMod = 1000000007; std::vector<std::vector<int>> f(n, std::vector<int>(m)); for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { f[i][j] = x; x = static_cast<int>(((1ll * x * a + b) ^ c) % kMod); } } auto Add = [&](int &x, int y) { x += y; if (x >= kMod) { x -= kMod; } }; int result = 0; for (int j = 0; j < n; ++j) { std::vector<int> s(m, 0); for (int i = 0; i < m; ++i) { for (int t = 0; t < m; ++t) { if (isGood[i + t] == 'Y') { Add(s[i], f[j][t]); } } } for (int i = 0; i < j; ++i) { int sum = 0; for (int k = 0; k < m; ++k) { Add(sum, static_cast<int>(1ll * f[i][k] * s[k] % kMod)); } result ^= sum; } } return result; } };