CSP-J2021 题解

分糖果

题意

选择L~R中的某个数 , 使得x mod k的结果最大。

思路

分两种情况考虑:

若 L 和 R 对 K 取模后在同一区间,则必然在 x=R 位置取到最大值;
否则 L~R 必然跨越多个区间,则取模后的结果必然有 k-1。
而对于是否在同一区间,在除以 k 后,商是否一致判断即可。

参考代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
  ll n, l, r;
  cin >> n >> l >> r;
  if (l / n != r / n) cout << n - 1 << endl;
  else cout << r % n << endl;
  return 0;
}

插入排序

题意

给定长度为 n 的整数序列 ,有 Q 种操作:

1:x v 修改序列 a 中的第 x 个元素 a[x] 为 v ,该操作次数不超过5000次;
2:x 将数组进行稳定排序,求原先第 x 个元素排序后的位置。

思路

不如维护将原先所有的 a 排序后的升序数组。对于所有操作,我们需要维护原位置到有序数组中的映射。

对于 1 操作,找到 a[x] 对应位置,显然修改值将使其往前或往后。联系到题目中提示的插入排序,可以不断向前/向后比较。注意同时维护映射关系。
对于 2 操作,直接输出映射即可。
注:如果该题中的数组长度更长、操作次数更多,我们可使用平衡树来解决该题。

参考代码

#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 8e3+5;
int a[N];
pii p[N];

int main() {
  ios::sync_with_stdio(false);
  int n, q; cin >> n >> q;
  for (int i = 1; i <= n; i++) {
    cin >> a[i];
    p[i] = {a[i], i};
  }
  sort(p + 1, p + 1 + n);
  for (int i = 1; i <= n; i++) a[p[i].second] = i;
  for (int i = 0, op, x, v; i < q; i++) {
    cin >> op; 
    // 5000 * 8000 = 4e7
    if (op == 1) {
      cin >> x >> v;
      int pos = a[x];
      p[pos].first = v;
      while (pos > 1 && p[pos] < p[pos - 1]) {
        swap(a[p[pos].second], a[p[pos - 1].second]);
        swap(p[pos], p[pos - 1]);
        pos--;
      } 
      while (pos < n && p[pos] > p[pos + 1]) {
        swap(a[p[pos].second], a[p[pos + 1].second]);
        swap(p[pos], p[pos + 1]);
        pos++;
      }
    } else {
      cin >> x;
      cout << a[x] << endl;
    }
  }
  return 0;
}

网络连接

题意

解析带端口的IP地址串,按服务器和客户端角色判断连接情况。

思路

若将带端口的IP地址串记为 a.b.c.d:e,则需要检查的项目有:

  • 有三个点号和一个冒号分隔字符串,且冒号出现在最后;
  • a,b,c,d,e均不为空,且不含有前导零;

可将对字符串的解析抽象为函数,简化代码逻辑。

参考代码

#include<bits/stdc++.h>
using namespace std;
map<string, int> dict;
const int IP = 256;
const int PORT = 65536;

bool check(string s, int limit) {
  // ".0.0.1:80" -> ""
  if (s.empty()) return false;
  // "0127.0.0.1:80" -> "0127"
  if (s[0] == '0' && s.size() > 1) return false;
  int val = 0;
  for (int i = 0; i < s.size(); i++) {
    val = val * 10 + s[i] - '0'; 
    if (val >= limit) return false;
  }
  return true;
}

bool parse(string ip) {
  string s = "";
  int dot_cnt = 0, port_cnt = 0;
  for (int i = 0; i < ip.size(); i++) {
    if (ip[i] == '.') dot_cnt += 1;
    if (ip[i] == ':') {
      if (dot_cnt != 3) return false;
      port_cnt += 1;
    }
    if (!isdigit(ip[i])) {
      if (!check(s, IP)) return false;
      s = "";
    } else s += ip[i];
  }
  return check(s, PORT) && dot_cnt == 3 && port_cnt == 1;
}

void process_server(string ip, int id) {
  bool valid = parse(ip);
  if (!valid) {cout << "ERR" << endl; return;}
  if (dict.count(ip)) {cout << "FAIL" << endl; return;}
  dict[ip] = id;
  cout << "OK" << endl;
}

void process_client(string ip) {
  bool valid = parse(ip);
  if (!valid) {cout << "ERR" << endl; return;}
  if (!dict.count(ip)) {cout << "FAIL" << endl; return;}
  cout << dict[ip] << endl;
}

int main() {
  ios::sync_with_stdio(false);
  int n; cin >> n;
  for (int i = 1; i <= n; i++) {
    string name, ip;
    cin >> name >> ip;
    if (name[0] == 'S') process_server(ip, i);
    else process_client(ip);
  }
  return 0;
}

小熊的果篮

题意

有两类共 n 个水果拍成一排,称连续的排在一起的同一种水果称为“块”。

每次将每一个“块”中最左边的水果同时挑出。重复该操作直至水果用完。

每次水果被挑出后“块”会发生动态变化。

思路

尝试建模每个块,使用块头来表示每个块的开始位置,即第一个元素或与上一个元素类型不同的位置。

每个元素之间使用双向链表相连接。

对于每次输出选出的元素,我们只需要依次输出块头元素,并从双向链表中删除该元素。

当块头元素输出后,需要更新块头列表。
考虑在原块头位置的下一个元素,只有当:

  • 该下一个元素与原块头位置的上一个元素类型不同;
  • 该下一个元素不是原块头。

则能够成为新的块头位置。

参考代码

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5+5;
struct Node {
  int pre, nxt, v;
}a[N];
vector<int> head, nxt_head;

int main() {
  ios::sync_with_stdio(false);
  int n; cin >> n;
  a[0].v = a[n + 1].v = -1;
  a[0].nxt = 1;
  a[n + 1].pre = n;
  for (int i = 1; i <= n; i++) {
    cin >> a[i].v;
    a[i].pre = i - 1;
    a[i].nxt = i + 1;
    if (a[i].v != a[i - 1].v) head.push_back(i);
  }
  while(head.size()) {
    nxt_head.clear();
    for (int id : head) {
      cout << id << " ";
      Node& node = a[id];
      a[node.pre].nxt = node.nxt;
      a[node.nxt].pre = node.pre;
      if (node.v == a[node.nxt].v && node.v != a[node.pre].v)
        nxt_head.push_back(node.nxt);
    }
    cout << endl;
    swap(head, nxt_head);
  }
  return 0;
}
posted @ 2022-08-08 19:09  ForeverCC  阅读(129)  评论(0编辑  收藏  举报
Live2D