CF1234(Div. 3) 题解(A to E)
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 里的 deque 和 map 来维护。
先将第一个聊天记录存入双端队列中,并标记一下。
再遍历一下,如果这个元素没有标记过,则插进双端队列的队首。
如果插入后双端队列的长度大于了 \(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;
}