Loading

abc 283

abc_283_d

abc 283 D

题意

当一个只包含小写字母,() 的字符串满足以下要求的时候,它就是一个 好的 字符串:去掉所有小写字母后,再一对一对地去掉括号,最后什么也不剩下。

例如 (a(ba)) 就是一个好的字符串。

现在给你一个字符串 \(s\)\(s\) 是一个好的字符串,对于它的每一个字符,都需要做一些操作:

  1. 如果 \(s_i\)(,什么也不做。

  2. 如果 \(s_i\) 是小写字符,将它放入盒子,如果盒子中有相同的,就晕倒。

  3. 如果 \(s_i\)),找到一个最大的整数 \(j\),使得 \(s_j \sim s_i\) 是一个好的字符串,将 \(s_j \sim s_i\) 中的所有小写字符从盒子中拿出来。

如果不会晕倒,输出 Yes,否则输出 No

思路

首先,我们可以想明白,对于每一个 ),都肯定只有一个配对的 (,又需要是最大的 \(j\),所以 \(j\) 肯定是那个和当前 ) 匹配的 ( 的下标。

既然如此,那么可以考虑用括号匹配的方法来解决这道题。

而括号匹配是用栈来实现的,所以考虑用栈来实现这道题。

每次先将自己这个字符放进去,再进行判断:

  1. 如果是 (,什么都不干。

  2. 如果是小写字符,标记(因为栈中不能有两个相同的字符)并放入栈中。

  3. 如果是 ),那么就从栈顶开始找,把遇见的所有字符全部取消标记,并弹出,直到找到 (

时间复杂度

因为栈中每个字符都只会进栈出栈一次,所以时间复杂度为 \(O(n)\)

代码

#include <bits/stdc++.h>

using namespace std;

string s;
bool f[30], flag = 1;

stack<int> st;

int main() {
  cin >> s;
  for (int i = 0; i < s.size(); i++) {
    if (s[i] == ')') {  // 如果是 )
      while (!st.empty() && st.top() != '(') {  // 当没找到 ( 且栈不为空
        f[st.top() - 'a'] = 0, st.pop();  // 取消标记并弹出
      }
      st.pop();  // 将 ( 弹出
    } else {
      st.push(s[i]);  // 压入栈中
      if ('a' <= s[i] && s[i] <= 'z') {  // 如果是小写字符
        if (f[s[i] - 'a']) {   // 如果出现过
          flag = 0; 
          break;
        }
        f[s[i] - 'a'] = 1;  // 标记
      }
    }
  }
  cout << (flag ? "Yes" : "No");
  return 0;
}

abc_283_e

abc 283 e

题意

给定一个 \(h \times w\) 的矩阵 A,每个元素要么是 0,要么是 1\(a_{i, j}\) 表示第 \(i\) 行第 \(j\) 列的数。

你可以做很多次操作:选择一个 \(i\) \((1 \le i \le h)\),将第 \(i\) 行的所有 \(s_{i, j}\) \((1 \le j \le w)\) 都翻转(0 变为 11 变为 0)。

\(a_{i, j}\) 的所有相邻格子都和它不同时,称 \(a_{i, j}\) 为孤立的。

请你求出最少需要多少次操作能使得 A 中没有孤立的点,如果不能,输出 -1

思路

首先,有一个很简单的做法,就是枚举每一行是翻还是不翻,总时间复杂度为 \(2 ^ {h \times w}\),当然,这样时间复杂度过大,所以不考虑搜索。

那既然想到搜索,就不难看出,这是个子集搜索。

既然是子集搜索,那是不是可以考虑用 dp 来实现呢?(01 背包)

dp[i][0/1][0/1] 表示第 \(i\) 行翻还是不翻,第 \(i - 1\) 行翻还是不翻,并且前 \(i - 1\) 行没有孤立点的最小翻转次数。

所以就可以得到转移方程为 dp[i][j][k] = min(dp[i - 1][k][0], dp[i - 1][k][1]) + j

当然,在每次取最小值的时候,需要判断是否满足没有孤立点这个条件。

时间复杂度

枚举每一行,\(O(h)\)

检查是否存在孤立点,\(O(w)\)

总时间复杂度为 \(O(h \times w)\)

代码

#include <bits/stdc++.h>

using namespace std;

const int H = 1010, W = 1010;

const int dx[] = {0, 1, 0, -1};
const int dy[] = {1, 0, -1, 0};

int h, w, dp[H][2][2];
bool a[H][W];

bool P(int i, int j) {  // 检查是否为孤立点
  bool flag = 0;
  for (int f = 0; f < 4; f++) {
    int nx = i + dx[f], ny = j + dy[f];
    if (1 <= nx && nx <= h && 1 <= ny && ny <= w && a[i][j] == a[nx][ny]) {
      flag = 1;
      break;
    }
  }
  return flag;
}

bool F(int i, int j, int k, int l) {  // 检查是否不存在孤立点
  for (int f = 1; f <= w; f++) {
    a[i][f] ^= j, a[i - 1][f] ^= k, a[i - 2][f] ^= l;
  }
  bool flag = 1;
  for (int f = 1; f <= w; f++) {
    flag &= P(i - 1, f);
  }
  for (int f = 1; f <= w; f++) {
    a[i][f] ^= j, a[i - 1][f] ^= k, a[i - 2][f] ^= l;
  }
  return flag;
}

int main() {
  cin >> h >> w;
  for (int i = 1; i <= h; i++) {
    for (int j = 1; j <= w; j++) {
      cin >> a[i][j];
    }
  }
  // 初始化
  for (int i = 1; i <= h; i++) {
    for (int j = 0; j < 2; j++) {
      for (int k = 0; k < 2; k++) {
        dp[i][j][k] = h + 1;
      }
    }
  }
  dp[1][0][0] = 0, dp[1][1][0] = 1;
  for (int i = 2; i <= h; i++) {
    for (int j = 0; j < 2; j++) {
      for (int k = 0; k < 2; k++) {
        for (int l = 0; l < 2; l++) {
          if (dp[i - 1][k][l] != h + 1 && F(i, j, k, l)) {
            dp[i][j][k] = min(dp[i][j][k], dp[i - 1][k][l] + j);
          }
        }
      }
    }
  }
  // 求答案
  int ans = h + 1;
  for (int i = 0; i < 2; i++) {
    for (int j = 0; j < 2; j++) {
      if (dp[h][i][j] != h + 1 && F(h + 1, 0, i, j)) {
        ans = min(ans, dp[h][i][j]);
      }
    }
  }
  cout << (ans == h + 1 ? -1 : ans);
  return 0;
}
posted @ 2023-03-02 22:47  chengning0909  阅读(13)  评论(0编辑  收藏  举报