CF1234(Div. 3) 题解(A to E)

发布时间 2023-10-04 17:40:51作者: cyf1208

A Equalize Prices Again 题解

题目大意

\(n\) 个商品,每个商品价格为 \(a_i\),求一个最小的价格 \(x\),使得不亏本(即 \(\sum\limits_{i=1}^n{(a_i-x)}\ge0\))。

解题思路

输出平均数向上取整(即 \(\left\lceil(\sum\limits_{i=1}^n{a_i})\div n\right\rceil\))即可。

代码

#include<bits/stdc++.h>
using namespace std;
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  int t;
  cin >> t;
  while(t--) {
    int n, x, sum = 0;
    cin >> n;
    for(int i = 1; i <= n; i++) {
      cin >> x;
      sum += x;
    }
    cout << (sum % n == 0 ? sum / n : sum / n + 1) << "\n";
  }
  return 0;
}

B1 & B2 Social Network 题解

题目大意

维护一个长度最多为 \(k\) 的序列,每次加入一个数 \(x\),如果 \(x\) 在序列中,则不进行任何操作。否则将 \(x\) 插入序列头部,序列长度超过 \(k\) 时舍弃超出的部分。求所有操作结束后序列的长度和内容。

解题思路

模拟,用 STL 里的 dequemap 来维护。
先将第一个聊天记录存入双端队列中,并标记一下。
再遍历一下,如果这个元素没有标记过,则插进双端队列的队首。
如果插入后双端队列的长度大于了 \(k\),那么将队尾的元素弹出,并取消标记。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int a[N];
deque<int> dq;
map<int, int> mp;
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  int n, k;
  cin >> n >> k;
  for(int i = 1; i <= n; i++) {
    cin >> a[i];
  }
  dq.push_front(a[1]);
  mp[a[1]] = 1;
  for(int i = 2; i <= n; i++) {
    if(!mp[a[i]]) {
      dq.push_front(a[i]);
      mp[a[i]] = 1;
      if(dq.size() > k) {
        mp[dq.back()] = 0;
        dq.pop_back();
      }
    }
  }
  cout << dq.size() << "\n";
  while(!dq.empty()) {
    cout << dq.front() << " ";
    dq.pop_front();
  }
  return 0;
}

C Pipes 题解

题目大意

给定 \(2 \times n\) 的管道网络,给出每个格子的管道类型,每个格子可以旋转任意次 \(90\) 度。求从 \((1, 0)\) 向右流入的水流是否能够从 \((2, n)\) 向右流出。

解题思路

从终点出发,可以发现只有对于这两种水管都只有一种选择的可能,我们这样就必然可以推导到下一个位置,如果不能那么就说明不能通水。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int t, n;
char s[3][N];
inline bool dfs(int x, int y, int nx, int ny) {
  if(x == 1 && y == 0) {
    return 1;
  }
  if(y == 0) {
    return 0;
  }
  if(s[x][y] <= '2') {
    if(x == nx) {
      return dfs(x, y - 1, x, y);
    } else {
      return 0;
    }
  } else {
    if(x == nx) {
      return dfs(x % 2 + 1, y, x, y);
    } else {
      return dfs(x, y - 1, x, y);
    }
  }
}
int main() {
  cin >> t;
  while(t--) {
    cin >> n;
    scanf("%s%s", s[1] + 1, s[2] + 1);
    bool f = dfs(2, n, 2, n + 1);
    if(!f) {
      cout << "NO\n";
    } else {
      cout << "YES\n";
    }
  }
  return 0;
}

D Distinct Characters Queries 题解

题目大意

一个字符串 \(s\),和 \(q\) 个操作(包括以下两个):

  • 1 pos c\(s_{\text{pos}}\) 上的字符变为 \(c\)
  • 2 l r 询问 \([l,r]\) 中有多少个不同的字符。

解题思路

树状数组板子题。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
string s;
int t, n, sum[30][N];
inline int lowbit(int x) {
  return x & (-x);
}
inline void add(int x, int k, int v) {
  for(int i = x; i <= n; i += lowbit(i)) {
    sum[k][i] += v;
  }
}
inline int getsum(int x, int k) {
  int sum1 = 0;
  for(int i = x; i >= 1; i -= lowbit(i)) {
    sum1 += sum[k][i];
  }
  return sum1;
}
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> s;
  n = s.size();
  for(int i = 1; i <= n; i++) {
    add(i, s[i - 1] - 'a', 1);
  }
  cin >> t;
  while(t--) {
    int f, l, r, x;
    char c;
    cin >> f;
    if(f == 1) {
      cin >> x >> c;
      add(x, c - 'a', 1);
      add(x, s[x - 1] - 'a', -1);
      s[x - 1] = c;
    } else {
      cin >> l >> r;
      int ans = 0;
      for(int i = 0; i < 26; i++) {
        ans += ((getsum(r, i) - getsum(l - 1, i)) ? 1 : 0);
      }
      cout << ans << "\n";
    }
  }
  return 0;
}

E Special Permutations 题解

题目大意

定义排列 \(p_i(n) = [i, 1, 2, \dots\, i - 1, i + 1, \dots, n]\),定义 \(pos(p, val)\) 表示 \(val\) 在排列 \(p\) 中的位置,给定序列 \(x\),定义函数 \(f(p) = \sum\limits_{i=1}^{m - 1} |pos(p, x_i) - pos(p, x_{i + 1})|\),求 \(f(p_1)\)\(f(p_n)\)

解题思路

模拟、数学。我们可以发现排列的变化:

 1 2 3 4
 2 1 3 4
 3 1 2 4
 4 1 2 3

\(i\) 个排列与第 \(i-1\) 个排列,只有两个数字的位置不同,这说明我们在计算第 \(i\) 个排列的答案时,只需要考虑在上一个答案的基础上,单独计算变动位置的那两个数字所产生的影响即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, m, x[N];
vector<int> e[N];
long long sum;
int main() {
  ios::sync_with_stdio(0);
  cin.tie(0), cout.tie(0);
  cin >> n >> m;
  for(int i = 1; i <= m; i++) {
    cin >> x[i];
    if(i != 1 && x[i] != x[i - 1]) {
      e[x[i]].push_back(x[i - 1]);
      e[x[i - 1]].push_back(x[i]);
      sum += abs(x[i] - x[i - 1]);
    }
  }
  cout << sum << " ";
  for(int i = 2; i <= n; i++) {
    long long cnt1 = 0, cnt2 = 0;
    for(int j = 0; j < e[i - 1].size(); j++) {
      int v = e[i - 1][j];
      if(v > i - 1) {
        cnt1 += v - 1;
      } else {
        cnt1 += v;
      }
    }
    for(int j = 0; j < e[i].size(); j++) {
      int v = e[i][j];
      if(v == i - 1) {
        continue;
      }
      if(v < i) {
        cnt2 += i - v - 1;
      } else {
        cnt2 += v - i;
      }
    }
    sum -= (cnt1 + cnt2);
    cnt1 = cnt2 = 0;
    for(int j = 0; j < e[i].size(); j++) {
      int v = e[i][j];
      if(v < i) {
        cnt1 += v;
      } else {
        cnt2 += v - 1;
      }
    }
    for(int j = 0; j < e[i - 1].size(); j++) {
      int v = e[i - 1][j];
      if(v == i) {
        continue;
      }
      if(v < i - 1) {
        cnt2 += i - 1 - v;
      } else {
        cnt2 += v - i;
      }
    }
    sum += cnt1 + cnt2;
    cout << sum << " ";
  }
  return 0;
}