稠州常规赛18题解
T1括号画家
本题有暴力做法,就是枚举
优化思路
容易想到利用栈进行匹配判断。
考虑其实这个字符串如果优美,其实只要看栈是否为空即可,那么我们可以用栈进行字符串匹配,那么我们只需要枚举
优化思路2
本题可以考虑进行DP优化,我们记录上次匹配的点,然后下次遇到可以匹配的时候,只需要查询一下前置是否合法即可,这样子就可以进行合法的转移!时间复杂度
代码略
T2数阵K小值
思路1暴力
考虑直接生成数列,然后sort即可,期望40分
思路2二分
容易发现,每行通过
左界为
因为当前的乘数
代码略
T3或表达式
思路
本题还是考察分治思想,我们考虑|,对于|,其实就是分段了,相当于每个|就是
对于括号,就像是多了一次计算即可!
代码
int dfs() {
int ans = 0;
while (cin >> c) {
if (c == 'a')
ans++;
else if (c == '(')
ans += change();
else if (c == '|')
return max(ans, change());
else if (c == ')')
return ans;
}
return ans;
}
T4集合等分
思路
容易看出,本题考察背包,因为在数字组成方案的时候,我们可以用01dfs,也可以用01背包来推方案数量。
划分集合的时候,我们发现
那么考虑优化,我们可以滚动进行压缩维度!
今天我们讲解第二种思路!
对于组合我们容易观察到,枚举出来的组合并不是任意两个进行配对的,也就是
那么令
所以,我们去考虑问题的时候,请同学们务必想明白它的含义和由来,例如整数划分、数字组成类型的背包,其实包含了集合的含义在里面,希望大家能明白其背后的意义!
T5流浪猫
思路
本题是一个环形,容易想到破环成链,一般来说有两种方法,一种是复制一份,然后直接求解
另外如果
那么我们考虑在dp,因为可以喂两次,所以我们考虑1喂食的dp一次,然后1不喂食的dp一次即可!
代码
dp[1][0] = INF;
dp[1][1] = a[1];
for (ll i = 2; i <= n; ++i) {
dp[i][0] = dp[i - 1][1];
dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]) + a[i];
}
ans = min(dp[n][0], dp[n][1]);
dp[1][0] = 0;
dp[1][1] = INF;
for (ll i = 2; i <= n; ++i) {
dp[i][0] = dp[i - 1][1];
dp[i][1] = min(dp[i - 1][0], dp[i - 1][1]) + a[i];
}
ans = min(ans, dp[n][1]);
T6 树上K路径
思路
考虑暴力,就是dfs出来一个点,然后深下去k,有多少条即可,如果是链条的数据,就可以卡住。
那么考虑如何优化,考虑
for (int j = 0; j < k; j++)
ans += dp[rt][j] * dp[to][k - j - 1];
接下来是第二个转移,这个转移还是比较清晰的,就是表示对于父节点rt来说,深度j+1的节点数量可以由儿子节点to深度+1转移而来。
for (int j = 0; j < k; j++)
dp[rt][j + 1] += dp[to][j];
当然本题可以有书上点分治的做法,这里不展开讲!
代码
void dfs(int rt, int fa) {
dp[rt][0] = 1;
for (auto to : G[rt]) {
if (to != fa) {
dfs(to, rt);
for (int j = 0; j < k; j++)
ans += dp[rt][j] * dp[to][k - j - 1];
for (int j = 0; j < k; j++)
dp[rt][j + 1] += dp[to][j];
}
}
}