题目链接
题目解析
A.6192. 公因子的数目
AC代码
class Solution {
public:
int commonFactors(int a, int b) {
int t = std::min(a, b);
int ans = 0;
for (int i = 1; i <= t; ++i) {
if (a % i == 0 && b % i == 0) ++ans;
}
return ans;
}
};
思路分析
没什么说的,数据量很小,闭着眼模拟就是了。
B.2428. 沙漏的最大总和
AC代码
class Solution {
public:
int maxSum(vector<vector<int>>& grid) {
constexpr int MAXN = 7;
array<std::pair<int, int>, MAXN> aux = {{
{0, 0}, {0, 1}, {0, 2},
{1, 1},
{2, 0}, {2, 1}, {2, 2},
}};
int n = grid.size() - 2;
int m = grid[0].size() - 2;
int ans = -1;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
int tmp = 0;
for (int k = 0; k < MAXN; ++k) {
tmp += grid[i + aux[k].first][j + aux[k].second];
}
ans = std::max(ans, tmp);
}
}
return ans;
}
};
思路分析
仍旧是简单模拟,就是写的有些慢。
C.2429. 最小 XOR
AC代码
class Solution {
public:
int minimizeXor(int num1, int num2) {
constexpr int MAXN = 32;
std::bitset<MAXN> n1(num1), n2(num2), n3;
int t = n2.count();
for (int i = MAXN - 1; i >= 0; --i) {
if (t == 0) break;
if (n1.test(i)) {
n3.set(i);
--t;
}
}
for (int i = 0; i < MAXN; ++i) {
if (t == 0) break;
if (!n1.test(i)) {
n3.set(i);
--t;
}
}
return static_cast<int>(n3.to_ullong());
}
};
思路分析
也是一个简单的模拟题:为了让最后的数字^num1最小,就要尽可能消掉高位的1,如果所有的1都消掉了,那么就尽可能填充低位的0。如果用位操作可能还是有些繁琐,容易出错,但是使用bitset
直接掉方法,简单又方便。
D.2430. 对字母串可执行的最大删除数
AC代码
class Solution {
vector<int> memo;
int aux(const string &s, int begin, int end, int cnt) {
if (end - begin < 2) return cnt + 1;
if (~memo[begin]) return memo[begin] + cnt;
int mid = (begin + end) / 2;
// int n1 = mid - 1, n2 = mid - begin + mid - 1;
int n1 = begin, n2 = begin + 1;
//[begin, mid) [mid, end)
//[begin, n1] [, n2]
while (n1 < mid) {
if (s[n1] != s[n2]) {
++n1; n2 += 2;
continue;
}
bool flag = true;
for (int i = n1 - 1, j = n2 - 1; i >= begin; --i, --j) {
if (s[i] != s[j]) {
flag = false;
break;
}
}
if (flag) {
if (end - n1 > memo[begin]) memo[begin] = std::max(memo[begin], aux(s, n1 + 1, end, 1));
else break;
}
++n1; n2 += 2;
}
if (~memo[begin]) return memo[begin] + cnt;
else return (memo[begin] = 1) + cnt;
}
public:
int deleteString(string s) {
memo.resize(s.size(), -1);
return aux(s, 0, s.size(), 0);
}
};
思路分析
当时比赛的时候丝毫没有想到DP,我对动态规划的确不太熟悉,就想着用一个贪心,先去掉长的重复串,再去掉短的,当时想着短的无论如何后面还可以再去掉,所以应该是比较优的。结果实现了一下,发现对于多个重复的串还是不行。贪心不行就想改成搜索,还是很机灵地加上了记忆化搜索,但是还是超时,没有办法必须考虑剪枝。剪枝的策略:如果后面的字符个数比当前的最大操作数大,再去搜索,这样可以解决的原因在于对于有多个重复字符的串,由于是从小串开始删除,所以会导致操作数很大,一旦搜索到大串的时候就会直接跳出。一共有O(n)种状态,每个状态都需要O(n)复杂度进行搜索,因此总的复杂度是O(n^2)的。
总体代码实现很优雅、紧凑, 我自己很满意。我觉得得益于在实现之前先对一个稍微复杂的串进行手动模拟,加上对于搜索、记忆化、剪枝这些技术逐渐熟稔,所以能够在有效的时间里面实现出一个sophisticated的代码。
当时遇到了三个bug:
- 是在搜索的过程中保存的是前一个串和后一个串的末尾,在修改搜索方向后忘记末尾应该指向
begin
而让其指向了0 - 在加上记忆化搜索后有点分不清楚状态的定义和函数返回值的定义,函数的返回值应该是对当前串
[begin, end)
在cnt
次搜索情况下进行搜索的最大删除方案,而记忆化搜索保存的是对当前串[begin, end)
进行搜索的最大删除方案 - 剪枝刚开始没有跳出循环,所以还是超时
看了一下题解,发现记忆化搜索和DP只不过是两种不同的思考方向。
周赛总结
优点
- 思路灵活
缺点
- 代码能力有待提高,对于记忆化搜索+剪枝这一套组合拳还是不够熟悉
改进方案
多做题