本文是 AtCoder Beginner Conteset(ABC)397 的总结笔记。
A - Thermometer Problem:A - Thermometer
题目: 模拟。
非常简单的签到题。
题目中已经明说了小数只有一位,所以这里用 double
或者 float
都可以,一般更推荐使用 double
。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;void solve () { double a; cin >> a; if (a >= 38.0 ) cout << 1 << endl; else if (a < 37.5 ) cout << 3 << endl; else cout << 2 << endl; } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve (); return 0 ; }
B - Ticket Gate Log Problem:B - Ticket Gate Log
贪心。
思路也非常的简单。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;string s; void solve () { cin >> s; int res = 0 ; for (int i = 0 ; i < s.size (); i++) { if (s[i] == 'i' && i + 1 < s.size () && s[i + 1 ] == 'o' ) { i++; continue ; } res += 1 ; } cout << res << endl; } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve (); return 0 ; }
C - Variety Split Easy Problem:C - Variety Split Easy
题目: (题目是 F 题的简化版)
给定长度为 N 的整数序列 。
在中间某一位置,将 A 分割为两个非空集合。求两个集合不同整数计数之和的最大值。
约束条件:
思路: 思路 1: 简单来说需要解决下面几个问题:
如何求出集合中的不同整数的个数?
使用 unordered_set
就可以去除重复数字,得到集合的大小。
如何维护集合中各个元素的个数?
使用 cnt
数组来维护。index 是元素的值,value 是元素的个数。
时间复杂度 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;const int N = 3e5 + 10 ;int num[N], cnt[N]; unordered_set<int > num_left, num_right; int n, x;void solve () { cin >> n; for (int i = 1 ; i <= n; i++) { cin >> x; num[i] = x; cnt[x]++; num_right.insert (x); } int res = 0 ; for (int i = 1 ; i <= n; i++) { x = num[i]; num_left.insert (x); cnt[x]--; if (cnt[x] == 0 && num_right.count (x) > 0 ) num_right.erase (x); res = max (res, (int )(num_left.size () + num_right.size ())); } cout << res << endl; } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve (); return 0 ; }
思路 2: 提前预处理出来 pre
和 suc
数组,分别表示“从前往后”和“从后往前”看,截止每个位置的不重复数字的个数。
时间复杂度
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;const int N = 3e5 + 10 ;int num[N]; int pre[N], suc[N];unordered_set<int > s; int n, x;void solve () { cin >> n; for (int i = 1 ; i <= n; i++) cin >> num[i]; for (int i = 1 ; i <= n; i++) { s.insert (num[i]); pre[i] = s.size (); } s.clear (); for (int i = n; i >= 1 ; i--) { s.insert (num[i]); suc[i] = s.size (); } int res = 0 ; for (int i = 1 ; i <= n - 1 ; i++) res = max (res, pre[i] + suc[i + 1 ]); cout << res << endl; } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve (); return 0 ; }
D - Cubes Problem:D - Cubes
题目: 给定正整数 N。求满足 的正整数对 。如果不存在,输出 -1
约束条件:
思路: Tips:long long
的最大值是
如果直接枚举 x 和 y 的话,时间复杂度大约为 ,肯定是不能被接受的。理想的时间复杂度应该是 或者 。
那么最好的思路应该是:枚举一个数,然后快速的算出另一个数,判断是否满足条件。
推导思路如下:
通过上面的流程,就可以在枚举 a 的情况下,快速计算出 b,同时快速计算出 x 和 y 的值。(注意流程中的几个隐藏条件即可)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;LL N; void solve () { cin >> N; for (LL a = 1 ; a * a <= N / a; a++) { if (N % a == 0 ) { LL b = N / a; LL z = a * a - b; if (z % 3 == 0 ) { z /= 3 ; if (a * a - 4 * z >= 0 ) { LL root = sqrt (a * a - 4 * z); LL y = (-a + root) / 2 ; if (y > 0 && (-a + root) % 2 == 0 ) { LL x = y + a; if (x * x * x - y * y * y == N) { cout << x << " " << y << endl; return ; } } } } } } cout << -1 << endl; } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve (); return 0 ; }
补充题目: Problem:D - I hate Factorization
这道题目和本题类似,但是难度大大降低。
我们首先考虑一个数列:
简单计算一下这个数列,可以得到下列数据:
1 2 3 4 5 6 7 n = 1: value = 1 n = 2: value = 31 n = 3: value = 211 n = 4: value = 781 …………………… n = 118: value = 953097211 n = 119: value = 985959031
从上面可以知道,前后两个数的五次方之间的差,第一次超过 1e9
是在下标为 120
的时候。
如果两个数之间差距越大,那么他们五次方的差超过 1e9 的速度就越快。从上可以知道,实际上我们仅仅遍历 [-120,120]
之间的数其实就够枚举出答案了。
使用最暴力的全枚举,或者引入 map 预先保存预处理的五次方值,均可以解出本题。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;LL X; void solve () { cin >> X; unordered_map<LL, LL> mp; for (int a = -120 ; a < 121 ; a++) mp[1ll * a * a * a * a * a] = a; for (pair<LL, LL> d : mp) { LL b5 = d.first, b = d.second; if (mp.count (X + b5)) { LL a = mp[X + b5]; cout << a << " " << b << endl; return ; } } } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve (); return 0 ; }
E - Path Decomposition of a Tree Problem:E - Path Decomposition of a Tree
树状 DP + DFS
题目: 给定一棵树,有 个节点,编号为 。有 条无向边。
判断这棵树是否能被分解为 N 条长度为 K 的路径。
更准确的说,是否存在一个 的矩阵 P,满足:
矩阵的所有元素是 的一种排列。 矩阵中的元素中, 和 之间有边相连。(即矩阵中每一行,前后两个节点间都有边) 约束条件:
思路: 详细思路如下图所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #include <bits/stdc++.h> using namespace std;typedef long long LL;typedef pair<int , int > PII;const int NK = 2e5 + 10 ;vector<int > G[NK]; int n, k, sz[NK];void NO () { cout << "No" << endl; exit (0 ); } void dfs (int u, int fa) { sz[u] = 1 ; int son = 0 ; for (int v : G[u]) if (v != fa) { dfs (v, u); if (sz[v]) { son++; sz[u] += sz[v]; } } if (sz[u] < k) { if (u == 1 || son > 1 ) NO (); } else if (sz[u] == k) { if (son > 2 ) NO (); sz[u] = 0 ; } else NO (); } void solve () { cin >> n >> k; for (int i = 1 ; i < n * k; i++) { int u, v; cin >> u >> v; G[u].push_back (v), G[v].push_back (u); } dfs (1 , 0 ); cout << "Yes" << endl; } int main () { cin.tie (0 ); ios_base::sync_with_stdio (false ); solve (); return 0 ; }
F - Variety Split Hard(TODO) Problem:F - Variety Split Hard
线段树
题目: 给定长度为 N 的整数序列 。
在中间某两个位置,将 A 分割为三个非空集合。求三个集合不同整数计数之和的最大值。
约束条件:
思路: C 题中只切了一刀,分割为了两个集合。
本题中是切了两刀,分割为了三个集合。