abc 283
abc_283_d
题意
当一个只包含小写字母,(
,)
的字符串满足以下要求的时候,它就是一个 好的 字符串:去掉所有小写字母后,再一对一对地去掉括号,最后什么也不剩下。
例如 (a(ba))
就是一个好的字符串。
现在给你一个字符串 \(s\),\(s\) 是一个好的字符串,对于它的每一个字符,都需要做一些操作:
-
如果 \(s_i\) 是
(
,什么也不做。 -
如果 \(s_i\) 是小写字符,将它放入盒子,如果盒子中有相同的,就晕倒。
-
如果 \(s_i\) 是
)
,找到一个最大的整数 \(j\),使得 \(s_j \sim s_i\) 是一个好的字符串,将 \(s_j \sim s_i\) 中的所有小写字符从盒子中拿出来。
如果不会晕倒,输出 Yes
,否则输出 No
。
思路
首先,我们可以想明白,对于每一个 )
,都肯定只有一个配对的 (
,又需要是最大的 \(j\),所以 \(j\) 肯定是那个和当前 )
匹配的 (
的下标。
既然如此,那么可以考虑用括号匹配的方法来解决这道题。
而括号匹配是用栈来实现的,所以考虑用栈来实现这道题。
每次先将自己这个字符放进去,再进行判断:
-
如果是
(
,什么都不干。 -
如果是小写字符,标记(因为栈中不能有两个相同的字符)并放入栈中。
-
如果是
)
,那么就从栈顶开始找,把遇见的所有字符全部取消标记,并弹出,直到找到(
。
时间复杂度
因为栈中每个字符都只会进栈出栈一次,所以时间复杂度为 \(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
题意
给定一个 \(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
变为 1
,1
变为 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;
}