• 牛客小白月赛22


    题目传送门

    官方题解传送门

    A .操作序列

    sol:如果STL熟悉,那么就是一道模拟题。就是输入有点奇葩。但是看了官方题解中提到了平衡树。嗯,没错,map和set的底层都是平衡树。红黑树不会,平衡树觉得还是fhq-treap好敲。所以,提供一份map的解法和一份fhq-treap的解法。

    • map
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      map<int, int> mp;
      int main() {
          int t; scanf("%d", &t);
          while (t--) {
              int n, m, op; char c;
              scanf("%d%c", &n, &c);
              if (c == ' ') {
                  scanf("%d", &m);
                  bool ok = true;
                  for (int i = n - 30; i <= n + 30; i++)
                      if (mp.count(i)) ok = false;
                  if (ok) mp[n] = m;
                  continue;
              }
              if (n == -1) {
                  if (mp.empty()) puts("skipped");
                  else {
                      printf("%d
      ", mp.begin()->second);
                      mp.erase(mp.begin());
                  }
              } else {
                  if (mp.count(n)) printf("%d
      ", mp[n]);
                  else puts("0");
              }
          }
          return 0;
      }
      View Code
    • fhq-treap
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 1e6 + 10;
      struct Treap {
          int key, val;
          int rand;
          int lson, rson;
      } node[MAXN];
      int root, tot;
      int new_node(int n, int k) {
          int i = ++tot;
          node[i].key = n;
          node[i].val = k;
          node[i].rand = rand();
          node[i].lson = node[i].rson = 0;
          return i;
      }
      void split(int rt, int& a, int& b, int k) {
          if (rt == 0) {
              a = b = 0;
              return;
          }
          if (node[rt].key <= k) {
              a = rt;
              split(node[rt].rson, node[a].rson, b, k);
          } else {
              b = rt;
              split(node[rt].lson, a, node[b].lson, k);
          }
      }
      void merge(int& rt, int a, int b) {
          if (a == 0 || b == 0) {
              rt = a + b;
              return;
          }
          if (node[a].rand < node[b].rand) {
              rt = a;
              merge(node[rt].rson, node[a].rson, b);
          } else {
              rt = b;
              merge(node[rt].lson, a, node[b].lson);
          }
      }
      void insert(int n, int k) {
          int a, b, c;
          split(root, root, c, n + 30);
          split(root, a, b, n - 30 - 1);
          if (b == 0) b = new_node(n, k);
          merge(root, a, b);
          merge(root, root, c);
      }
      int pop(int& point) {
          if (node[point].lson == 0) {
              int tmp = node[point].val;
              point = node[point].rson;
              return tmp;
          }
          return pop(node[point].lson);
      }
      int get_val(int n) {
          int a, b, c;
          split(root, root, c, n);
          split(root, a, b, n - 1);
          int tmp;
          if (b == 0) tmp = 0;
          else tmp = node[b].val;
          merge(root, a, b);
          merge(root, root, c);
          return tmp;
      }
      int main() {
          int t; scanf("%d", &t);
          while (t--) {
              int n, k; char c;
              scanf("%d%c", &n, &c);
              if (c == ' ') {
                  scanf("%d", &k);
                  insert(n, k);
              } else if (n == -1) {
                  if (root == 0) puts("skipped");
                  else printf("%d
      ", pop(root));
              } else {
                  printf("%d
      ", get_val(n));
              }
          }
          return 0;
      }
      View Code

      fhq-treap真的是平衡树里最简单的了,这么久没敲还能凭对代码的记忆而不是代码的理解一次敲对。

    B .树上子链

    sol:和求树的直径差不多,树的直径是求树上最长的链,这题转化成求权值最大的链。

    • 树的直径
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const LL INF = 0x3f3f3f3f3f3f3f3f;
      const int MAXN = 1e5 + 10;
      vector<int> edge[MAXN];
      int val[MAXN];
      LL res = -INF;
      LL dfs(int u, int f) {
          LL max1 = 0, max2 = 0;
          for (int v : edge[u]) {
              if (v == f) continue;
              LL val = dfs(v, u);
              if (val > max2) max2 = val;
              if (max2 > max1) swap(max1, max2);
          }
          res = max(res, max1 + max2 + val[u]);
          return max1 + val[u] > 0 ? max1 + val[u] : 0;
      }
      int main() {
          int n; scanf("%d", &n);
          for (int i = 1; i <= n; i++)
              scanf("%d", &val[i]);
          for (int i = 2; i <= n; i++) {
              int u, v;
              scanf("%d%d", &u, &v);
              edge[u].push_back(v);
              edge[v].push_back(u);
          }
          dfs(1, -1);
          printf("%lld
      ", res);
          return 0;
      }
      View Code

    C .交换游戏

    sol:看了题解后感觉是一个挺裸的记忆化搜索。补掉了。

    • 记忆化搜索
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 1 << 12 | 10;
      int dp[MAXN];
      int read() {
          int n = 0;
          char c = getchar();
          while (c != '-' && c != 'o') c = getchar();
          while (c == '-' || c == 'o') {
              n = n << 1 | (c == 'o');
              c = getchar();
          }
          return n;
      }
      int dfs(int n) {
          if (dp[n] != -1) return dp[n];
          int tmp = n, cnt = 0;
          while (tmp) {
              cnt ++;
              tmp -= tmp & -tmp;
          }
          dp[n] = cnt;
          int a = 1, b = 2, c = 4;
          for (int i = 1; i <= 10; i++) {
              if ((n & a) && (n & b) && !(n & c)) {
                  dp[n] = min(dp[n], dfs(n ^ a ^ b ^ c));
              }
              if (!(n & a) && (n & b) && (n & c)) {
                  dp[n] = min(dp[n], dfs(n ^ a ^ b ^ c));
              }
              a <<= 1, b <<= 1, c <<= 1;
          }
          return dp[n];
      }
      int main() {
          memset(dp, -1, sizeof(dp));
          int t; scanf("%d", &t);
          while (t--) {
              int n = read();
              printf("%d
      ", dfs(n));
          }
          return 0;
      }
      View Code

    D .收集纸片

    sol:比赛的时候想着爆搜整张地图然后代码也没实现出来,题目中的纸片最多只有10张,所以突破口在纸片,可以枚举所以的收集顺序。那么枚举的方法就有很多了。官方题解中用了dfs的方法,那么我这里就用next_premutation这个函数来解决了。这个函数在蓝桥杯中也被多次考到。

    • 全排列
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const int INF = 0x3f3f3f3f;
      PII p[20]; int order[20];
      int main() {
          int t; scanf("%d", &t);
          while (t--) {
              scanf("%*d%*d%d%d", &p[0].first, &p[0].second);
              int n; scanf("%d", &n);
              for (int i = 1; i <= n; i++) {
                  scanf("%d%d", &p[i].first, &p[i].second);
                  order[i] = i;
              }
              order[n + 1] = 0;
              int res = INF;
              do {
                  int sum = 0;
                  for (int i = 1; i <= n + 1; i++) {
                      sum += abs(p[order[i]].first - p[order[i - 1]].first);
                      sum += abs(p[order[i]].second - p[order[i - 1]].second);
                  }
                  if (sum < res) res = sum;
              } while (next_permutation(order + 1, order + 1 + n));
              printf("The shortest path has length %d
      ", res);
          }
          return 0;
      }
      View Code

      原来给出的地图大小是没用的

    E .方块涂色

    sol:总共$n$行,被涂了$r$行,还剩$(n - r)$行。总共$m$列,被涂了$c$列,还剩$(m - c)$列,所以答案就是$(n - r) * (m - c)$。注意到结果可能爆int就不会错了。

    • 数学
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      int main() {
          int n, m, r, c;
          while (~scanf("%d%d%d%d", &n, &m, &r, &c)) 
              printf("%lld
      ", 1LL * (n - r) * (m - c));
          return 0;
      }
      View Code

    F .累乘数字

    sol:听说有人拿到题就直接用python高精度上了。也是一种不错的选择,容易抢一血。不过更高效的方法就是输出$n$之后再输出$d$次$00$。

    • python大数
      while True :
          try :
              n, m = map(int, input().split())
              print(n * 100 ** m)
          except : 
              break
      View Code
    • 数学
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      int main() {
          int n, m;
          while (~scanf("%d%d", &n, &m)) {
              printf("%d", n);
              for (int i = 1; i <= m; i++)
                  printf("00");
              puts("");
          }
          return 0;
      }
      View Code

    G .仓库选址

    sol:一种比较直白的方式是枚举每个位置做仓库,然后算出这个位置的花费,然后找出最小值。复杂度是$O((n * m) * (n * m))$。官方题解就是这种方法,参照官方题解。但是其实可以把行和列分开考虑使复杂度变成$O((n * m) + (n * m))$。

    • 思维
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<LL, LL> PII;
      const LL INF = 0x3f3f3f3f;
      const LL MAXN = 110;
      LL row[MAXN], col[MAXN];
      LL cal(LL* arr, LL len) {
          LL res = INF;
          for (LL i = 1; i <= len; i++) {
              LL sum = 0;
              for (LL j = 1; j <= len; j++)
                  sum += abs(i - j) * arr[j];
              res = min(res, sum);
          }
          return res;
      }
      int main() {
          LL t; scanf("%lld", &t);
          while (t--) {
              LL n, m, k;
              scanf("%lld%lld", &m, &n);
              memset(row, 0, sizeof(row));
              memset(col, 0, sizeof(col));
              for (LL i = 1; i <= n; i++) {
                  for (LL j = 1; j <= m; j++) {
                      scanf("%lld", &k);
                      row[i] += k;
                      col[j] += k;
                  }
              }
              printf("%lld
      ", cal(row, n) + cal(col, m));
          }
          return 0;
      }
      View Code

    H .货物种类

    sol:关键是差分,然后我是用map来维护的

    • 差分
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 1e5 + 10;
      map<int, int> pre[MAXN], now;
      int main() {
          int n, m;
          scanf("%d%d", &n, &m);
          for (int i = 1; i <= m; i++) {
              int l, r, d;
              scanf("%d%d%d", &l, &r, &d);
              pre[l][d] ++;
              pre[r + 1][d] --;
          }
          int res, cnt = 0;
          for (int i = 1; i <= n; i++) {
              for (auto it : pre[i]) {
                  now[it.first] += it.second;
                  if (now[it.first] == 0)
                      now.erase(it.first);
              }
              if (now.size() > cnt) {
                  cnt = now.size();
                  res = i;
              }
          }
          printf("%d
      ", res);
          return 0;
      }
      View Code

    I .工具人

    J .计算A + B

    sol:skipped的情况有'+'在最前面,'+'在最后面,'+'的次数不为1。剩下的就是高精度了。反正我是用python水过去的,python大数和split真香。至于C++,之后再补上吧。

    • python大数
      t = int(input())
      for i in range(t) :
          n = input().split('+')
          if len(n) != 2 or n[0] == '' or n[1] == '':
              print('skipped');
          else :
              print(int(n[0]) + int(n[1]))
      View Code

    ps:一血的代码太精华了,佩服佩服,贴个传送门

    --------------------------------------------------前来填坑--------------------------------------------------

    • 高精度模拟
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 10010;
      struct BigInt {
          const static int mod = 10000;
          const static int dlen = 4;
          int a[600], len;
          BigInt() {
              memset(a, 0, sizeof(a));
              len = 1;
          }
          BigInt(const char* s) {
              memset(a, 0, sizeof(a));
              int l = strlen(s); len = 0;
              for (int i = l - 1; i >= 0; i -=  dlen) {
                  int tmp = 0, start = max(0, i - 4 + 1);
                  for (int j = start; j <= i; j++)
                      tmp = tmp * 10 + (s[j] ^ '0');
                  a[len ++] = tmp;
              }
          }
          friend BigInt operator + (BigInt a, BigInt b) {
              BigInt res;
              res.len = max(a.len, b.len);
              int tmp = 0;
              for (int i = 0; i < res.len; i++) {
                  tmp += a.a[i] + b.a[i];
                  res.a[i] = tmp % mod;
                  tmp /= mod;
              }
              if (tmp) res.a[res.len ++] = tmp;
              return res;
          }
          void output() {
              printf("%d", a[len - 1]);
              for (int i = len - 2; i >= 0; i--)
                  printf("%04d", a[i]);
              puts("");
          }
      };
      char s[MAXN];
      int find_plus(const char* s) {
          int res = -1;
          for (int i = 0; s[i]; i++) {
              if (s[i] == '+') {
                  if (res != -1) return -1;
                  else res = i;
              }
          }
          return res;
      }
      int main() {
          int t; scanf("%d", &t);
          while (t--) {
              scanf("%s", s);
              int index = find_plus(s);
              if (index == -1 || index == 0 || s[index + 1] == '') {
                  puts("skipped");
              } else {
                  s[index] = '';
                  BigInt a(s), b(s + index + 1);
                  BigInt res = a + b;
                  res.output();
              }
          }
          return 0;
      }
      View Code

      仿照kuangbin大佬的模板代码自己写了一个比较骚的高精度。中间写错了两次。看样子还是很有必要写这份C++版的。

  • 相关阅读:
    ajax获取后台数据,显示到input输入框里面
    js的比较运算符含义和示例和逻辑运算符
    Vue的 on +bind+if +for
    Vue入门例子
    Spring-AOP
    fatal: remote origin already exists git出现这个
    springmvc-文件上传下载
    springmvc-ajax
    查询Id最大的基础上+1
    bootstrap select去掉右边小三角
  • 原文地址:https://www.cnblogs.com/Angel-Demon/p/12354729.html
Copyright © 2020-2023  润新知