Problem A. Suborrays

笔者的直觉告诉自己,构造一个单峰的排列即可,但没想到任何排列都满足情况。

时间复杂度 $\mathcal O(n)$

#include <cstdio>
#include <vector>

using namespace std;

int main() {
  int t;
  scanf("%d", &t);
  while (t--) {
    int n;
    scanf("%d", &n);
    int cnt = 1; 
    vector<int> ans; 
    for (; cnt <= n; cnt += 2) ans.push_back(cnt);
    cnt -= 2; 
    if (cnt + 1 == n) 
      ++cnt;
    else 
      --cnt; 
    for (; cnt >= 1; cnt -= 2) ans.push_back(cnt);
    for (auto i : ans) printf("%d ", i);
    puts("");
  }
  return 0; 
}

Problem B. Fix You

因为每一个格子只会有 $R$ 或者 $D$,那么显然不合法的情况只存在于靠在边界,并且连着外面的情况。

时间复杂度 $\mathcal O(nm)$

#include <cstdio>

using namespace std;

int main() {
  int t;
  scanf("%d", &t);
  while (t--) {
    int n, m, ans = 0; 
    scanf("%d %d", &n, &m);
    for (int i = 1; i <= n; ++i) {
      char s[m + 1];
      scanf("%s", s); 
      for (int j = 0; j < m; ++j) {
        if (s[j] == 'D' && i == n) 
          ++ans;
        if (s[j] == 'R' && j == m - 1) 
          ++ans; 
      }
    }
    printf("%d\n", ans);
  }
  return 0; 
}

Problem C. Cyclic Permutations

考虑合法方案的构造方法。

排列内部一定存在 ${a,b,c}$ 这样一个子序列,满足 $b\le a,c$ 的情况。

所以答案为 $n!-2^{n-1}$,其中 $2^{n-1}$ 为所有数放到一边的情况。

时间复杂度 $\mathcal O(n)$

#include <cstdio>

using namespace std;

typedef long long ll;

const int P = 1e9 + 7;

int main() {
  int n; 
  scanf("%d", &n);
  int ans = 1, t = 1; 
  for (int i = 1; i <= n; ++i) ans = (ll)ans * i % P; 
  for (int i = 1; i < n; ++i) t = (ll)t * 2 % P; 
  printf("%d\n", (ans - t + P) % P);
  return 0;
}

Problem D. 505

显然不可能存在 $4\times 4$ 及以上的子矩阵,因为 $4$ 个奇数的和为偶数,那么行数就 $\leq 3$。

考虑状压 DP,令 $f[i][j]$ 表示前 $i$ 列合法,且第 $i$ 列的状态为 $j$ 的最少修改次数。

$$ f[i+1][mask]=Min\{f[i][j]+fix(mask)\} $$

其中 $fix(mask)$ 是将原矩阵的状态修改成 $mask$ 的修改次数。

时间复杂度 $\mathcal O(m\times 2^{2n})$

#include <iostream>
#include <vector>

using namespace std;

template <class T> 
void chkmax(T& x, T y) { x = x > y ? x : y; }

template <class T>
void chkmin(T& x, T y) { x = x < y ? x : y; }

int n, m;
vector<string> s;

int calc(int mask, int j) {
  int res = 0; 
  for (int i = 0; i < n; ++i) 
    if ((mask >> i & 1) != (s[i][j] - '0')) 
      ++res; 
  return res; 
}

bool check(int a, int b) {
  for (int i = 0; i < n - 1; ++i) 
    if (((a >> i & 1) + (a >> i + 1 & 1) + (b >> i & 1) + (b >> i + 1 & 1)) % 2 == 0) 
      return 0; 
  return 1; 
}

int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr); 
  cin >> n >> m; 
  if (n >= 4) {
    cout << -1 << '\n';
    return 0; 
  }
  s.resize(n); 
  for (int i = 0; i < n; ++i) cin >> s[i];
  vector<vector<int>> dp(m, vector<int>(1 << n, 1e9)); 
  for (int mask = 0; mask < 1 << n; ++mask) dp[0][mask] = calc(mask, 0);
  for (int i = 0; i < m - 1; ++i) 
    for (int c_mask = 0; c_mask < 1 << n; ++c_mask) 
      for (int n_mask = 0; n_mask < 1 << n; ++n_mask) 
        if (check(c_mask, n_mask)) 
          chkmin(dp[i + 1][n_mask], dp[i][c_mask] + calc(n_mask, i + 1));
  int ans = 1e9; 
  for (int mask = 0; mask < 1 << n; ++mask) chkmin(ans, dp[m - 1][mask]); 
  cout << ans << '\n';
  return 0;
}

Problem E. Pairs of Pairs

Task 1 的做法就只需要找到深度最深的一个节点并判断即可。

Task 2 我们考虑 dfs 后对于深度相同的节点进行配对。

对于同一深度的点对配对一定不存在导出子图的边,而深度差 $1$ 的点对配对最多存在 $2$ 条导出子图上的边。

时间复杂度 $O(n)$

#include <cstdio>
#include <vector>
#include <functional>

using namespace std;

int main() {
  int t;
  scanf("%d", &t);
  while (t--) {
    int n, m;
    scanf("%d %d", &n, &m);
    vector<vector<int>> g(n); 
    for (int i = 0; i < m; ++i) {
      int u, v; 
      scanf("%d %d", &u, &v);
      --u, --v;
      g[u].push_back(v);
      g[v].push_back(u);
    }
    vector<int> dep(n), fa(n); 
    int max_dep = 0;
    function<void(int u, int fa)> dfs = [&](int u, int fp) {
      dep[u] = dep[fp] + 1; 
      fa[u] = fp; 
      if (dep[u] > dep[max_dep]) 
        max_dep = u; 
      for (auto v : g[u]) 
        if (!dep[v]) 
          dfs(v, u); 
    };
    dfs(0, 0); 
    if (dep[max_dep] >= (n + 1) / 2) {
      printf("PATH\n%d\n", dep[max_dep]); 
      int u = max_dep; 
      do 
        printf("%d ", u + 1); 
      while (u = fa[u]); 
      printf("1"); 
    } else {
      printf("PAIRING\n"); 
      vector<vector<int>> dp(dep[max_dep]); 
      for (int i = 0; i < n; ++i) dp[dep[i] - 1].push_back(i);
      int ans = 0; 
      for (int i = 0; i < dep[max_dep]; ++i) ans += (dp[i].size() >> 1); 
      printf("%d\n", ans); 
      for (int cur_dep = 0; cur_dep < dep[max_dep]; ++cur_dep) 
        for (unsigned i = 0; i < dp[cur_dep].size() - 1; i += 2) printf("%d %d\n", dp[cur_dep][i] + 1, dp[cur_dep][i + 1] + 1); 
    }
    puts(""); 
  }
  return 0; 
}
最后修改:2020 年 09 月 06 日 03 : 49 PM
如果觉得我的文章对你有用,请随意赞赏