本文是 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 的路径。
更准确的说,是否存在一个
矩阵的所有元素是 矩阵中的元素中, 约束条件: 
思路: 详细思路如下图所示:
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 题中只切了一刀,分割为了两个集合。
本题中是切了两刀,分割为了三个集合。