topcoder srm 580 div1 [FINISHED] (贪心, 区间统计, dp)
problem1 link
最优选择一定是在$2n$个端点中选出两个。
problem2 link
分开考虑每个区间。设所有区间的左端点的最大值为$lc$,所有区间的右端点的最小值为$rc$.对于某个区间$L$,其实就是找最少的区间(包括$L$)能够完全覆盖区间$[lc,rc]$.
设$L$的左右端点为$L_{1},L_{2}$。考虑从$L_{1}$向左扩展,每次扩展一定是找一个区间$p$满足$p_{2}\geq L_{1}$且使得$p_{1}$最小。右端点向右扩展类似。
problem3 link
对于后手来说,它一定是每次只放置一个障碍格子在先手目前的位置。否则,如果放置了太多,那么先手就容易决策出向左还是向右比较好。
对于先手来说,假设目前先手在$(r,c)$,那么如果$(r,c)$和$(r+1,c)$之间没有障碍,且轮到先手,应该直接跳到$(r+1,c)$,否则,那么由后手的策略来看,此时已经有的障碍一定是一个包含$(r,c)$的区间,此时先手可以尝试向左或者向右运动到障碍区间外一个格子。
这样就可以用$(r,c,left,right,tag)$来表示一个状态来进行动态规划。$(r,c)$表示先手目前的位置,$(left, right)$表示目前障碍的区间,$tag$指示目前是先手还是后手。
code for problem1
#include <vector> class EelAndRabbit { public: int getmax(std::vector<int> &l, std::vector<int> t) { const int n = static_cast<int>(l.size()); int ans = 0; for (int i = 0; i < n; ++i) { for (int j = 0; j < 2; ++j) { int p1 = j == 0 ? -t[i] : -t[i] - l[i]; for (int k = 0; k < n; ++k) { for (int r = 0; r < 2; ++r) { int p2 = r == 0 ? -t[k] : -t[k] - l[k]; if (p1 != p2) { int num = 0; long long mask = 0; for (int x = 0; x < n; ++x) { if ((-t[x] - l[x] <= p1 && p1 <= -t[x]) || (-t[x] - l[x] <= p2 && p2 <= -t[x])) { if ((mask & (1ll << x)) == 0) { ++num; mask |= 1ll << x; } } } ans = std::max(ans, num); } } } } } return ans; } };
code for problem2
#include <algorithm> #include <string> #include <vector> constexpr int N = 2500; constexpr int M = 10000; int s[N], t[N]; int back[M], next[M]; int back_cost[M], next_cost[M]; int sort_idx[N]; class ShoutterDiv1 { public: int count(const std::vector<std::string>& s1000, const std::vector<std::string>& s100, const std::vector<std::string>& s10, const std::vector<std::string>& s1, const std::vector<std::string>& t1000, const std::vector<std::string>& t100, const std::vector<std::string>& t10, const std::vector<std::string>& t1) { int n = 0; for (const auto& e : s1000) { n += static_cast<int>(e.size()); } for (int i = 0; i < n; ++i) { s[i] = t[i] = 0; sort_idx[i] = i; } for (int i = 0; i < M; ++i) { back[i] = next[i] = i; } Parse(s1000, s, 1000); Parse(s100, s, 100); Parse(s10, s, 10); Parse(s1, s, 1); Parse(t1000, t, 1000); Parse(t100, t, 100); Parse(t10, t, 10); Parse(t1, t, 1); int c_left = t[0]; int c_right = s[0]; for (int i = 0; i < n; ++i) { back[t[i]] = std::min(back[t[i]], s[i]); next[s[i]] = std::max(next[s[i]], t[i]); c_left = std::min(c_left, t[i]); c_right = std::max(c_right, s[i]); } for (int i = M - 2; i >= 0; --i) { back[i] = std::min(back[i], back[i + 1]); } for (int i = 1; i < M; ++i) { next[i] = std::max(next[i], next[i - 1]); } for (int i = 0; i < M; ++i) { if (i <= c_left) { back_cost[i] = 0; } else if (i == back[i]) { back_cost[i] = -1; } else { if (back_cost[back[i]] == -1) { back_cost[i] = -1; } else { back_cost[i] = 1 + back_cost[back[i]]; } } } for (int i = M - 1; i >= 0; --i) { if (i >= c_right) { next_cost[i] = 0; } else if (i == next[i]) { next_cost[i] = -1; } else { if (next_cost[next[i]] == -1) { next_cost[i] = -1; } else { next_cost[i] = 1 + next_cost[next[i]]; } } } auto Cost = [&](int left, int right) { if (back_cost[left] == -1 || next_cost[right] == -1) { return -1; } return back_cost[left] + next_cost[right]; }; std::sort(sort_idx, sort_idx + n, [&](int x, int y) { return s[x] < s[y] || (s[x] == s[y] && t[x] < t[y]); }); int result = 0; for (int i = 0; i < n; ++i) { int tmp = Cost(s[sort_idx[i]], t[sort_idx[i]]); for (int j = 0; j < N && s[sort_idx[j]] <= s[sort_idx[i]]; ++j) { if (t[sort_idx[i]] <= t[sort_idx[j]]) { int val = Cost(s[sort_idx[j]], t[sort_idx[j]]); if (val != -1 && (tmp == -1 || tmp > 1 + val)) { tmp = 1 + val; } } } if (tmp == -1) { return -1; } result += tmp; } return result; } private: void Parse(const std::vector<std::string>& d, int* data, int base) { int idx = 0; for (size_t i = 0; i < d.size(); ++i) { for (size_t j = 0; j < d[i].size(); ++j) { data[idx++] += (d[i][j] - '0') * base; } } } };
code for problem3
#include <cstring> #include <limits> #include <string> #include <vector> #include <iostream> constexpr int N = 50; constexpr int kEachUseBit = 16; constexpr int kRabbitTagBit = 31; constexpr int kEelTagBit = 15; constexpr int kMask = (1 << (kEachUseBit - 1)) - 1; using TType = unsigned int; TType rabbit_eel[N][N][N][N + 1]; int cost[N][N]; int h, w; class WallGameDiv1 { public: int play(const std::vector<std::string> &costs) { h = static_cast<int>(costs.size()); w = static_cast<int>(costs[0].size()); for (int i = 0; i < h; ++i) { cost[i][0] = costs[i][0] - '0'; for (int j = 1; j < w; ++j) { cost[i][j] = cost[i][j - 1] + costs[i][j] - '0'; } } memset(rabbit_eel, 0, sizeof(rabbit_eel)); // Iterator each row to avoid more depths of recursion. for (int i = h - 1; i >= 0; --i) { for (int j = 0; j < w; ++j) { Eel(i, j, j, j); } } int result = std::numeric_limits<int>::max(); for (int i = 0; i < w; ++i) { result = std::min(result, Cost(0, i, i) + Eel(0, i, i, i)); } return result; } private: bool Computed(const TType &val, bool is_rabbit) { if (is_rabbit) { return (val & (1u << kRabbitTagBit)) != 0; } else { return (val & (1u << kEelTagBit)) != 0; } } int GetCost(const TType &val, bool is_rabbit) { if (!Computed(val, is_rabbit)) { return -1; } if (is_rabbit) { return static_cast<int>((val >> kEachUseBit) & kMask); } else { return static_cast<int>(val & kMask); } } int SetCost(TType &val, bool is_rabbit, int cost) { if (is_rabbit) { val |= (static_cast<TType>(cost)) << kEachUseBit; val |= 1u << kRabbitTagBit; } else { val |= cost; val |= 1u << kEelTagBit; } return cost; } int Eel(int row, int col, int left, int right) { TType &val = rabbit_eel[row][col][left][right]; int result = GetCost(val, false); if (result != -1) { return result; } if (row == h - 1) { return SetCost(val, false, 0); } result = Rabbit(row, col, left, right); if (right - left < w - 1) { result = std::max(result, Rabbit(row, col, std::min(col, left), std::max(col + 1, right))); } return SetCost(val, false, result); } int Rabbit(int row, int col, int left, int right) { TType &val = rabbit_eel[row][col][left][right]; int result = GetCost(val, true); if (result != -1) { return result; } if ((left <= col) && (col < right)) { result = std::numeric_limits<int>::max(); if (left > 0) { result = Cost(row, left - 1, col - 1) + Eel(row, left - 1, left, right); } if (right < w) { result = std::min( result, Cost(row, col + 1, right) + Eel(row, right, left, right)); } } else { result = Cost(row + 1, col, col) + Eel(row + 1, col, col, col); } return SetCost(val, true, result); } int Cost(int row, int left, int right) { if (left <= right) { if (left == 0) { return cost[row][right]; } return cost[row][right] - cost[row][left - 1]; } return 0; } };