topcoder srm 705 div1
problem1 link
设有一个字母表$T$,对于一个单词$w$,若对于任意的$0\leq i< |w|-1$,满足$w_{i}$在$T$中的排名小于等于$w_{i+1}$在$T$中的排名,则称$s$在$T$中是合法的。给出一个仅包含小写字母的单词集合$S$,重新排列字母表$T$得到新的字母表$T^{'}$,使得$S$中每个单词在$T^{'}$下是合法的。问是否存在这样的$T^{'}$。
建立有向图。不存在环即可。可以拓扑排序或者用floyd判断。
problem2 link
有n个盒子。每个盒子有1个糖。有一个大小为$n*m$转换矩阵$T$。进行$10^{100}$次操作,每次操作如下:(1)选择一个$j,0\leq j< m$,对所有的$i,0\leq i< n$,将第$i$个盒子的糖倒入到第$T[i][j]$个盒子。问最后最少有几个盒子中有糖?
首先,每进行一次操作,有糖的盒子的数目不会变多。其次,假设一开始进行的操作序列为$S$,设这时候的状态为$x$,然后进行一个操作序列$P$,随后再进行一个操作序列$S$,设这时候的状态为$y$,那么$y$时有糖的盒子是状态$x$时有糖的盒子的子集。
基于这两个结果,操作的流程为:判断当前是否存在两个盒子,使得经过某个操作序列$P$后,这两个盒子在操作后合并到同一个盒子,那么就执行该操作序列$P$。直到不存在这样的两个盒子即可。
problem3 link
首先,按照每个灯进行高斯消元. 假设$m=5, n =8$,最后的样子假设如下
\begin{pmatrix}
1 & 0& 0& 0& 0& 0 & 0 & 0\\
0 & 1& 0& 0& 0& 0& 0& 0\\
0 & 0& 1& 0& 0& 0& 0& 0\\
1 & 1 & 0 & 0& 0 & 0 & 0& 0\\
0 & 0 & 1& 0& 0& 0& 0& 0
\end{pmatrix}
那么最后五个操作(最后五列)有没有都可以, 最后的答案乘以$2^{5}$就可以了.
现在的rank, $r=3$.如果r比较小,那么直接进行$2^{r}$的暴力枚举即可.否则,对剩下的$m-r$行进行dp即可.复杂度为$r*2^{m-r}$
code for problem1
#include <string> #include <vector> class AlphabetOrderDiv1 { public: std::string isOrdered(const std::vector<std::string> &words) { int g[26][26]; for (int i = 0; i < 26; ++i) { for (int j = 0; j < 26; ++j) { g[i][j] = i == j; } } for (const auto &s : words) { for (size_t j = 0; j + 1 < s.length(); ++j) { int x = s[j] - 'a'; int y = s[j + 1] - 'a'; g[x][y] = 1; } } for (int i = 0; i < 26; ++i) { for (int j = 0; j < 26; ++j) { for (int k = 0; k < 26; ++k) { g[j][k] |= g[j][i] & g[i][k]; } } } for (int i = 0; i < 26; ++i) { for (int j = 0; j < i; ++j) { if (g[i][j] != 0 && g[j][i] != 0) return "Impossible"; } } return "Possible"; } };
code for problem2
#include <algorithm> #include <vector> class MovingTokens { public: int move(int n, int m, const std::vector<int> &moves) { Init(n, m, &A); for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) { A[i][j] = moves[j * n + i]; } } this->n = n; this->m = m; Init(n, n, &f); std::vector<int> a(n, 1); while (true) { bool ok = false; std::vector<int> path; for (int i = 0; i < n && !ok; ++i) { for (int j = i + 1; j < n && !ok; ++j) { if (a[i] != 0 && a[j] != 0) { ++K; path.clear(); if (Dfs(i, j, &path)) { std::reverse(path.begin(), path.end()); ok = true; } } } } if (!ok) { break; } Transform(path, &a); } int cnt = 0; for (int i = 0; i < n; ++i) { if (a[i] != 0) { ++cnt; } } return cnt; } private: bool Dfs(int x, int y, std::vector<int> *path) { if (x == y) { return true; } if (f[x][y] == K) { return false; } f[x][y] = K; for (int j = 0; j < m; ++j) { if (Dfs(A[x][j], A[y][j], path)) { path->emplace_back(j); return true; } } return false; } void Transform(const std::vector<int> &path, std::vector<int> *a) { std::vector<int> b(n); for (int j : path) { for (int i = 0; i < n; ++i) { b[i] = a->at(i); a->at(i) = 0; } for (int i = 0; i < n; ++i) { a->at(A[i][j]) += b[i]; } } } void Init(int n, int m, std::vector<std::vector<int>> *a, int init = 0) { a->resize(n); for (int i = 0; i < n; ++i) { a->at(i).resize(m, init); } } std::vector<std::vector<int>> A; std::vector<std::vector<int>> f; int n, m; int K = 0; };
code for problem3
#include <string> #include <vector> class BrightLampsRemake { public: std::vector<long long> maxAndCount(const std::string &init, const std::vector<std::string> &buttons) { int n = static_cast<int>(buttons.size()); int m = static_cast<int>(init.size()); std::vector<int> a(m); for (int i = 0; i < m; ++i) { a[i] = init[i] - '0'; } std::vector<std::vector<int>> b(m, std::vector<int>(n, 0)); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { b[i][j] = buttons[j][i] - '0'; } } int rank = 0; while (true) { int new_row = -1; int new_col = -1; for (int i = rank; i < m && new_row == -1; ++i) { for (int j = rank; j < n; ++j) { if (b[i][j] != 0) { new_row = i; new_col = j; break; } } } if (new_row == -1) { break; } if (new_row != rank) { for (int i = 0; i < n; ++i) { std::swap(b[rank][i], b[new_row][i]); } std::swap(a[rank], a[new_row]); } if (new_col != rank) { for (int i = 0; i < m; ++i) { std::swap(b[i][new_col], b[i][rank]); } } for (int i = 0; i < n; ++i) { if (b[rank][i] != 0 && i != rank) { for (int j = 0; j < m; ++j) { b[j][i] ^= b[j][rank]; } } } ++rank; } if (rank <= 27) { std::vector<long long> mask(rank, 0); for (int i = 0; i < rank; ++i) { for (int j = 0; j < m; ++j) { if (b[j][i] != 0) { mask[i] |= 1ll << j; } } } long long c = 0; for (int i = 0; i < m; ++i) { if (a[i] != 0) { c |= 1ll << i; } } std::vector<long long> result = {-1, -1}; Dfs(0, c, mask, rank, &result); result[1] <<= n - rank; return result; } int p = m - rank; struct Node { int num = -1; int h = 0; long long c = -1; }; std::vector<std::vector<Node>> dp(2, std::vector<Node>(1 << p)); std::vector<int> c(rank, 0); for (int i = 0; i < rank; ++i) { for (int j = rank; j < m; ++j) { if (b[j][i] != 0) { c[i] |= 1 << (j - rank); } } } int x = 0; for (int i = rank; i < m; ++i) { if (a[i] != 0) { x |= 1 << (i - rank); } } dp[0][x].num = 0; dp[0][x].c = 1; int H = 0; int prev = 0; int curr = 1; auto Update = [&](int a, long long b, int h, Node *r) { if (r->h != h || a > r->num) { r->num = a; r->c = b; r->h = h; } else if (a == r->num) { r->c += b; } }; for (int i = 0; i < rank; ++i) { for (int j = 0; j < (1 << p); ++j) { const auto &e = dp[prev][j]; if (e.h != H || e.num < 0) { continue; } Update(e.num + 1 - a[i], e.c, H + 1, &(dp[curr][j ^ c[i]])); Update(e.num + a[i], e.c, H + 1, &(dp[curr][j])); } std::swap(curr, prev); ++H; } Node result; result.h = H; for (int i = 0; i < (1 << p); ++i) { if (dp[prev][i].h == H && dp[prev][i].num >= 0) { Update(dp[prev][i].num + GetNum(i), dp[prev][i].c, H, &result); } } return {result.num, result.c << (n - rank)}; } private: int GetNum(long long x) { return __builtin_popcountll(x); } void Dfs(int cur_depth, long long v, const std::vector<long long> &mask, int max_depth, std::vector<long long> *result) { if (cur_depth == max_depth) { long long t = GetNum(v); if (result->front() == t) { ++result->back(); } else if (result->front() < t) { result->front() = t; result->back() = 1; } } else { Dfs(cur_depth + 1, v ^ mask[cur_depth], mask, max_depth, result); Dfs(cur_depth + 1, v, mask, max_depth, result); } } };