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);
    }
  }
};
posted @ 2017-03-08 14:22  朝拜明天19891101  阅读(203)  评论(0编辑  收藏  举报