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);
}
}
};