2024-12-31 15:35阅读: 43评论: 0推荐: 0

AtCoder Beginner Contest 386(补题)

AtCoder Beginner Contest 386

C - Operate 1

https://atcoder.jp/contests/abc386/tasks/abc386_c

思路

简单的条件判断题

代码

#include <bits/stdc++.h>
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
int k;
std::string s, t;
std::cin >> k >> s >> t;
int n = s.size(), m = t.size(), ans = 0;
if (n == m){
for (int i = 0; i < n; i++){
if (s[i] != t[i]){
k -= 1;
if (k < 0) {
break;
}
}
}
if (k < 0) ans = 0;
else ans = 1;
}else if (n == m + 1){
int index = 0;
for (int i = 0; i < n; i++){
if (s[i] == t[index]){
index++;
}
}
if (index == m){
ans = 1;
}else{
ans = 0;
}
}else if (m == n + 1){
int index = 0;
for (int i = 0; i < m; i++){
if (t[i] == s[index]) index++;
}
if (index == n){
ans = 1;
}else{
ans = 0;
}
}else{
ans = 0;
}
std::cout << (ans == 0 ? "No\n" : "Yes\n");
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

D - Diagonal Separation

https://atcoder.jp/contests/abc386/tasks/abc386_d

思路

通过观察,可以发现,最后的棋盘中,黑色格子形成了一种阶梯状(左上三角形)的结构。也就是说,一个黑格子的左上的所有格子,必须都是黑格子。所以,如果一个已染色的黑格子的左上有白格子,那么一定是No。因此,“染色的黑格子的左上没有染色的白格子”是一个必要条件。

那么它是不是充分条件呢?是!只要我把所有的黑格子的左上全染黑,就得到了一个可行方案,因此该条件是充分条件,只要满足了,就可以输出Yes。

因此,只需检测每个黑格子的左上有没有白格子即可。暴力检测复杂度M^2会超时,可以考虑先把所有格子按照行升序排序,如果行相同就按照列升序,依次处理。

评述

最近在学离散化,看到这个N的范围还以为是离散化,上来就是做,结果题目都没有理解。【哭了】

代码

#include <bits/stdc++.h>
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
struct node{
int x, y;
bool is_b;
};
bool operator<(node a, node b){
return a.x != b.x ? a.x < b.x : a.y < b.y;
}
void solve(){
int n, m;
std::cin >> n >> m;
std::vector<node> v(m);
for (int i = 0; i < m; i++){
int a, b;
char c;
std::cin >> a >> b >> c;
v[i] = {a, b, c == 'B'};
}
std::sort(v.begin(), v.end());
int mn = n + 1;
for (auto nd : v){
if (nd.is_b){
if (nd.y >= mn){
std::cout << "No\n";
return;
}
}else{
mn = std::min(mn, nd.y);
}
}
std::cout << "Yes\n";
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

E - Maximize XOR

https://atcoder.jp/contests/abc386/tasks/abc386_e

思路

根据题目的所给的C(n,k)106,所以直接枚举所以情况就行。时间复杂度是KO(C(n,k)),但是考虑到 k 有可能很大,导致TLE。我们知道C(n,k)=C(n,nk),所以可以通过比较 k 和 n/2 的大小关系选择两种枚举方案,一种是在 n 个数中选 k 个,一种是 n 个数都选了,其中 n - k 个数需要去掉

代码

#include <bits/stdc++.h>
typedef std::pair<int, int> pii;
#define INF 0x3f3f3f3f
#define MOD 998244353
using i64 = long long;
const int N = 1e5+5;
void solve(){
int n, k;
std::cin >> n >> k;
std::vector<i64> v(n+1);
for (int i = 1; i <= n; i++){
std::cin >> v[i];
}
i64 ans = 0;
auto dfs = [&](auto self, int pos, int left, i64 sum) -> void {
if (left == 0){
ans = std::max(ans, sum);
return;
}
for (int i = pos + 1; i <= n; i++){
self(self, i, left - 1, sum ^ v[i]);
}
};
if (k < n / 2)
dfs(dfs, 0, k, 0);
else{
i64 presum = 0;
for (int i = 1; i <= n; i++) presum ^= v[i];
dfs(dfs, 0, n - k, presum);
}
std::cout << ans << '\n';
}
signed main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout<<std::setiosflags(std::ios::fixed)<<std::setprecision(2);
int t = 1, i;
for (i = 0; i < t; i++){
solve();
}
return 0;
}

F - Operate K

https://atcoder.jp/contests/abc386/tasks/abc386_f

思路:dp + 优化

这道题目是一道经典 DP 问题:
假设 S 的长度是 N,T 的长度是 M
dp[i][j] 代表将 S[1...i] 改成和 T[1...j] 一样,最少需要几次操作。
这样只需要判断 dp[N][M] 是否 <= K 即可。
转移方程:
dp[i][j]= min(

​ 删除一个字符,即 dp[i1][j]+1

​ 添加一个字符,即 dp[i][j1]+1

​ 更改一个字符,即 dp[i1][j1]+1

​ 这两个字符本身就匹配,要求 S[i]==T[j],此时对应 dp[i1][j1]
)
这样做的复杂度是 O(NM) 的,会超时。

但是注意到 K 很小,代表着 dp[i][j] 中,如果 |ij|>k,那么需要的操作次数一定比 K 多,也即,此时 dp[i][j] 一定 > k,计算它没有意义。
所以,我们只考虑 |ij|<=k 的 dp。这样的复杂度就是 O(NK) 的,j的值被i约束,可行的j的范围是[i30,i+30],所以直接从这个范围的起点开始枚举j就行了

评述

相比于做对这道题,学会这道题的优化技巧更加重要

代码

#include <bits/stdc++.h>
using namespace std;
int k;
int n, m;
string s, t;
int f[500010][60]; // f[i][x] 是 dp[i][i-30+x]
int get_dp(int i, int j) {
// 输入 i, j,返回 dp[i][j]
if (abs(i-j) > k) return 0x3f3f3f3f;
return f[i][j-i+30];
}
void solve() {
memset(f, 0x3f, sizeof(f));
f[0][30] = 0; // 对应 dp[0][0]
for (int i = 1; i <= k; ++i)
f[0][30+i] = i; // f[0][30+i] 对应 dp[0][i]
for (int i = 1; i <= k; ++i)
f[i][30-i] = i; // f[i][30-i] 对应 dp[i][0]
for (int i = 1; i <= n; ++i)
for (int x = 0; x < 60; ++x) {
int j = i-30+x;
if (j <= 0 || j > m)
continue;
int cur_dp = 0x3f3f3f3f;
cur_dp = min(cur_dp, get_dp(i-1, j)+1);
cur_dp = min(cur_dp, get_dp(i, j-1)+1);
cur_dp = min(cur_dp, get_dp(i-1, j-1)+1);
if (s[i] == t[j])
cur_dp = min(cur_dp, get_dp(i-1, j-1));
f[i][x] = cur_dp;
}
}
int main() {
cin >> k;
cin >> s >> t;
n = s.length();
m = t.length();
s = " " + s;
t = " " + t;
solve();
puts(get_dp(n, m) <= k ? "Yes" : "No");
return 0;
}

本文作者:califeee

本文链接:https://www.cnblogs.com/califeee/p/18644144

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   califeee  阅读(43)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.