当前位置: 首页 > news >正文

AtCoder Beginner Contest 408

A - Timeout

思路:给定一个单增数组,和一个最大间隔,判断数组是否严格满足间隔不大于最大间隔。这就是个水题,倒是读题理解了一会儿

/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);int n, s;cin >> n >> s;int pre = 0;bool awake = true;for (int i = 0; i < n; i++) {int t;cin >> t;if (t - pre > s) { awake = false; }pre = t;}if (awake) { cout << "Yes"; } else { cout << "No"; }return 0;
}

B - Compression

思路:给定一个数组,要求将数组内元素去重并从小到大排序。这个题的题意明显比上一题通俗易懂多了,方案也很简单,直接扔set里即可

/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);set<int> sets;int n;cin >> n;for (int i = 0; i < n; i++) {int a;cin >> a;sets.insert(a);}cout << sets.size() << endl;for (auto i: sets) {cout << i << " ";}cout << endl;return 0;
}

C - Not All Covered

思路:有n个线段覆盖二维区域,求最短被覆盖最少的点所覆盖的层数。这个看起来像是区间求和,想到树状数组。但在想想这只是个c题,应该不会这么难,于是想到,利用差分数组,通过维护区间的两头来构造最终的线段。这个思路还是挺经典的

/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;const int MAXM = 1e6 + 5;int guard[MAXM];int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);int n, m;cin >> n >> m;memset(guard, 0, sizeof guard);for (int i = 0; i < m; i++) {int l, r;cin >> l >> r;guard[l]++;guard[r + 1]--;}int minGuard = m;for (int i = 1; i <= n; i++) {guard[i] += guard[i - 1];// cout << guard[i] << " ";minGuard = min(minGuard, guard[i]);}cout << minGuard << endl;return 0;
}

D - Flip to Gather

思路:给定一个01字符串,每次操作可以将子串中的一位01互换,求最少得操作次数使得串中所有的1连续。

首先想到dp,按位dp,分全0,先0后1,先1后0和全1四种状态进行转移。后来发现先0后1和先1后0两种状态由于根本无法知道0和1的数量,因此无法进行转移,而宣告破产。之后又想到先将字符串变为全0或者全1,然后从边开始加数,但此时重新审题突然发现,其实先0后1最后0这种方案也是满足条件的。最终决定还是重回dp重新思考。

重新整理,其实有分全0(0),先0后1(01),先1后0(10),全1(1)和先0后1最后0(010)这五种方案。由于向后递归,因此过程中其实我们不用关注前缀0的数量,于是,全1和先0后1可以合并为包含部分0且1结尾([0]1),先1后0和先0后1最后0可合并为包含部分0后特定1加特定0([0]10)。那么转移方程就简单了。全0直接由自己加1转移来,部分0且1结尾可以由自己或者全0加1得来。部分0后特定1加特定0则可以由自己或者上述两种方案加0转移来

场景标识转移前当前位为1当前位为0
全00dp[0]dp[0]+1dp[0]
部分0且1结尾[0]1dp[1]min(dp[0],dp[1])min(dp[0],dp[1])+1
部分0后特定1加特定0[0]10dp[2]min(dp[0],dp[1],dp[2])+1min(dp[0],dp[1],dp[2])
/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;const int MAXM = 2e5 + 5;int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);int t;cin >> t;while (t--) {int n;cin >> n;string s;cin >> s;int dp[6];if (n <= 2) {cout << 0 << endl;} else {if (s[0] == '0' && s[1] == '0') {dp[0] = 0;dp[1] = 1;dp[2] = 0;} else if (s[0] == '0' && s[1] == '1') {dp[0] = 1;dp[1] = 0;dp[2] = 1;} else if (s[0] == '1' && s[1] == '0') {dp[0] = 1;dp[1] = 1;dp[2] = 0;} else if (s[0] == '1' && s[1] == '1') {dp[0] = 2;dp[1] = 0;dp[2] = 1;}for (int i = 2; i < n; i++) {if (s[i] == '1') {dp[3] = dp[0] + 1;dp[4] = min(dp[0], dp[1]);dp[5] = min(dp[2], dp[4]) + 1;} else {dp[3] = dp[0];dp[4] = min(dp[0] + 1, dp[1] + 1);dp[5] = min(dp[2], dp[4] - 1);}dp[0] = dp[3];dp[1] = dp[4];dp[2] = dp[5];}int re = min(min(dp[0], dp[1]), dp[2]);cout << re << endl;}// int num0 = 0;// int num1 = 0;// for (int i = 0; i < n; i++) {//     if (s[i] == '0') {//         num0++;//     } else {//         num1++;//     }// }// int re = min(num0, num1);// int current = num0;// for (int i = 0; i < n; i++) {//     if (s[i] == '1') {//         current++;//     } else {//         current--;//     }//     re = min(re, current);// }// current = num1;// for (int i = 0; i < n; i++) {//     if (s[i] == '1') {//         current--;//     } else {//         current++;//     }//     re = min(re, current);// }// cout << re << endl;}return 0;
}

此外,看了一下大佬们的做法,其实大部分大佬用的都是和我一样的方案,但又发现了另一种很巧妙的方案,即用前缀合暴力枚举不同1的开始位置所需进行的最少操作次数。首先,预处理 pre[k] 数组,表示前 k 位包含多少个0。假设区间 [i,j] 之间的数均为1,那么其实就是需要求第一段0,第二段1和第三段0分别需要操作多少次。

第一段0需要操作次数:i-pre[i-1]

第二段1需要操作次数:pre[j]-pre[i-1]

第三段0需要操作的次数:n-1-j +i- pre[n-1] + 2pre[j]-2pre[i-1]

求和即为 2pre[j]-j + i - 2pre[i-1] +n-1-pre[n-1]

要求上式的最小值,分解一下f(x) = 2pre[x]-x, t= i - 2pre[i-1] +n-1-pre[n-1]

那么原式就等于了 f(x)+t, 于是,从后往前遍历求解即可

首先初始化,假设 i=j=n-1, 原式即变成了 pre[n-1]- 2pre[n-2] +n-1

f(n-1)=2pre[n-1]-n+1

/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;const int MAXN = 2e5 + 5;
int pre[MAXN];int getPre(int x) {if (x >= 0) {return pre[x];}return 0;
}int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);int t;cin >> t;while (t--) {int n;cin >> n;string s;cin >> s;memset(pre, 0, sizeof pre);pre[0] = s[0] == '0' ? 1 : 0;for (int i = 1; i < n; i++) {pre[i] = pre[i - 1];if (s[i] == '0') {pre[i]++;}}int re = min(n - getPre(n - 1), getPre(n - 1) - 2 * getPre(n - 2) + n - 1);// cout << re << "*";int currentF = 2 * getPre(n - 1) - n + 1;for (int i = n - 2; i >= 0; i--) {int t = i - 2 * getPre(i - 1) + n - 1 - getPre(n - 1);currentF = min(currentF, 2 * getPre(i) - i);re = min(re, currentF + t);}cout << re << endl;}return 0;
}

E - Minimum OR Path 

思路:求图中1点到n点的最小路径或和。一开始想利用异或的各种性质之类的,但是最终无功而返,最典型的就是两个大数的或和可能比一个大数和一个小数的或和要小。不过倒是有个性质可以用,就是两个数的或和一定不小于其中任意一个数。于是考虑按位运算,从高位往低位进行枚举,找到所有能使当前位保持0的边,然后看一下能否使得1点和n点连通,如果不能,则当前位一定为1,不可避免。否则,当前位可以保持0

/*
Author Owen_Q
*/
#include <bits/stdc++.h>using namespace std;const int MAXN = 2e5 + 5;
int u[MAXN], v[MAXN], w[MAXN], pre[MAXN];int findPre(int x) {return x == pre[x] ? x : pre[x] = findPre(pre[x]);
}void unionUV(int u, int v) {int preU = findPre(u);int preV = findPre(v);if (preU != preV) {pre[preU] = preV;}
}bool check(int k, int n, int m) {for (int i = 1; i <= n; i++) {pre[i] = i;}for (int i = 0; i < m; i++) {if ((w[i] | k) == k) {unionUV(u[i], v[i]);}}// cout << k << " " << findPre(1) << " " << findPre(n) << endl;return findPre(1) == findPre(n);
}int main() {ios_base::sync_with_stdio(false), cin.tie(nullptr);int n, m;cin >> n >> m;for (int i = 0; i < m; i++) {cin >> u[i] >> v[i] >> w[i];}int re = 0;for (int i = 29; i >= 0; i--) {if (!check(re | (1 << i) - 1, n, m)) {re |= 1 << i;}}cout << re << endl;return 0;
}

相关文章:

  • 循环冗余码校验CRC码 算法步骤+详细实例计算
  • 【C】十六进制(Hex)与ASCII
  • okhttp 实现长连接的完整方案
  • 降低显存,优化性能方案 MHA MQA GQA MLA MFA
  • 《高等数学》(同济大学·第7版)第四章第一节不定积分的概念与性质
  • CMake测试find_package()命令的相关原理
  • 商品中心—2.商品生命周期和状态的技术文档
  • [FX5U-PLC] 变频器的多段速变频调速控制系统
  • 可视化如何全方位赋能销售工作
  • Windows 文件路径与文件名限制
  • 大数据零基础学习day1之环境准备和大数据初步理解
  • CMOS图像传感器系列--(五)HDR之大小像素技术
  • 菲尔斯特传感器,超声波风速风向传感器助力绿色能源发展
  • 基于STM32F103C8T6单片机双极性SPWM逆变(软件篇)
  • 【单片机期末】汇编试卷
  • 51单片机读取PCF8563时钟芯片
  • IMX6ULL--EPIT 定时器理论
  • Docker加入用户组
  • Android Wi-Fi 连接失败日志分析
  • CanFestival移植到STM32G4
  • 不会PS怎么建网站/推广优化
  • 如何做网站访问日志/企业网站管理系统
  • 做网站的公司现在还 赚钱吗6/深圳互联网营销
  • 让网站降权/论坛推广
  • 工业设计在线网站/百度总部
  • 餐饮加盟网站怎么做/中国seo