CF系列题解
Codeforces Round #789 (Div. 2)
题目
A. Tokitsukaze and All Zero Sequence
原题链接
A. Tokitsukaze and All Zero Sequence
题意
给定一个序列,可以进行如下操作:
- 将两个不同的数 a i , b i a_i,b_i ai,bi 变为 他们当中的最小值。
- 对于两个相同的数,我们可以将其中一个变为 0 0 0。
问将所有数变为 0 0 0 所需要的最少操作次数。
题解
思路
分类讨论:
- 当序列中存在 0 0 0,我们可以依次将所有的非零数通过操作1转化为 0 0 0,答案即为非零数的数量。
- 若不存在 0 0 0,我们看其中是否有相同的数,若存在相同的数,我们可以将其中一个变为 0 0 0,再把其他数进行思路1,答案即为 n n n。
- 若不存在相同数,我们可以先把两个数变相同,之后进行思路2,答案即为 n + 1 n+1 n+1。
实现上用了排序。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve()
{
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i ++ ) cin >> a[i];
sort(a.begin(), a.end());
if (a[0] == 0) {
int i = 0;
while (i < n && a[i] == 0) i ++ ;
cout << n - i << "\n";
} else {
bool flag = false;
for (int i = 0; i < n - 1; i ++ ) {
if (a[i] == a[i + 1]) {
flag = true;
break;
}
}
if (flag) {
cout << n << "\n";
} else {
cout << n + 1 << "\n";
}
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}
B1. Tokitsukaze and Good 01-String (easy version)
原题链接
B1. Tokitsukaze and Good 01-String (easy version)
题意
给定一个 01
字符串,倘若每个连续的相同(即全为 0
或全为 1
)的段其长度为偶数,我们则认为其是好的。问将一个字符串变好需要的最少操作次数。
题解
思路
由于要求每段长度是偶数,那么(下标从
0
0
0 开始)应该满足
s
0
=
s
1
,
s
2
=
s
3
,
.
.
.
s_0=s_1,s_2=s_3,...
s0=s1,s2=s3,...,对于不满足的情况我们需要改变其中一个,因此 ans++
。
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
void solve()
{
int n;
cin >> n;
string s;
cin >> s;
int ans = 0;
for (int i = 0; i + 1 < n; i += 2) {
if (s[i] != s[i + 1]) {
ans ++ ;
}
}
cout << ans << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}
B2. Tokitsukaze and Good 01-String (hard version)
原题链接
B2. Tokitsukaze and Good 01-String (hard version)
题意
上一题的扩展,在满足最小操作次数的同时要使得段数尽可能少,问操作次数和最小的段数。
题解
思路
比赛又写了一大坨代码,回头理一理思路再写。
代码
#include <bits/stdc++.h>
using namespace std;
void solve()
{
int n;
cin >> n;
string s;
cin >> s;
int ans0 = 0, res0 = 0;
bool flag = false;
vector<int> id(n / 2);
for (int i = 0; i < s.size(); i ++ ) {
if(i == 0) {
if(s[i] == '0') flag = true;
res0 ++;
} else {
if(flag == true) {
if(s[i] == '1' && (res0 & 1)) {
s[i] = '0';
ans0 ++;
res0 ++;
id[i /2] = 2;
} else if(s[i] == '1' && res0 % 2 == 0) {
flag = false;
res0 = 1;
} else {
res0 ++;
}
} else if(flag == false) {
if(s[i] == '0' && (res0 & 1)) {
s[i] = '1';
ans0 ++;
res0 ++;
id[i / 2] = 2;
} else if(s[i] == '0' && res0 % 2 == 0) {
flag = true;
res0 = 1;
} else {
res0 ++;
}
}
}
}
n = id.size();
for (int i = 0; i < s.size(); i += 2) {
if (id[i / 2] != 2) {
if (s[i] == '1') id[i / 2] = 1;
else id[i / 2] = 0;
}
}
int la = -1, res = 1, res1 = 1, res2 = 1;
if(id[0] == 2) {
id[0] = 1;
la = 1;
for(int i = 1; i < n; i ++ ) {
if(id[i] == 2 || id[i] == la) {
continue;
} else {
la = id[i];
res1 ++;
}
}
id[0] = 0;
la = 0;
for(int i = 1; i < n; i ++ ) {
if(id[i] == 2 || id[i] == la) {
continue;
} else {
la = id[i];
res2 ++;
}
}
res = min(res1, res2);
} else {
for(int i = 0; i < n; i ++ ) {
if(la == -1) {
la = id[i];
continue;
} else {
if(id[i] == 2 || id[i] == la) {
continue;
} else {
la = id[i];
res ++;
}
}
}
}
cout << ans0 << ' ' << res << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}
C. Tokitsukaze and Strange Inequality
原题链接
C. Tokitsukaze and Strange Inequality
题意
给定排列 p p p,求满足 p a < p c , p b > p d p_a<p_c,p_b>p_d pa<pc,pb>pd 的四元组 [ a , b , c , d ] ( 1 ≤ a < b < c < d ≤ n ) [a,b,c,d] (1≤a<b<c<d≤n) [a,b,c,d](1≤a<b<c<d≤n) 的个数。
题解
思路
由数据范围可知复杂度 O ( n 2 ) O(n^2) O(n2),因此肯定是枚举,我们可以枚举 b , c b, c b,c, a a a 即为 b b b 的左边比 c c c 小的数, d d d 即为 c c c 的右边比 b b b 小的数,然后就发现很像树状数组求逆序对啊!!!
考虑一下复杂度, l o g ( 5000 ) log(5000) log(5000) 也就是个常数,而且1.5s时限,加上cf神机,虽然好像时间有点紧,但应该能过。
(带火们好像大多用的是前缀和呜呜呜,太菜了想不到)
代码
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
template <typename T>
struct Fenwick {
const int n;
vector<T> tr;
Fenwick(int n) : n(n), tr(n) {}
int lowbit(int x) {
return x & -x;
}
void add(int x, T v) {
for (int i = x; i < n; i += lowbit(i)) tr[i] += v;
}
T query(int x) {
T res = 0;
for (int i = x; i; i -= lowbit(i)) res += tr[i];
return res;
}
T rangeSum(int l, int r) {
return query(r) - query(l - 1);
}
};
void solve()
{
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i ++ ) cin >> a[i];
Fenwick<int> fen1(n + 1), fen2(n + 1);
i64 ans = 0;
for (int b = 2; b <= n - 2; b ++ ) {
fen1.add(a[b - 1], 1);
for (int c = n - 1; c > b; c -- ) {
fen2.add(a[c + 1], 1);
ans += fen2.query(a[b] - 1) * fen1.query(a[c] - 1);
}
for (int c = n - 1; c > b; c -- ) fen2.add(a[c + 1], -1); // 注意还原
}
cout << ans << "\n";
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T -- ) {
solve();
}
return 0;
}