CF1011(Div.2)A~D
A.Serval and String Theory(思维)
题意
给出一个字符串’S’,你可以对该字符串进行至少 k k k次以下操作:
- 选择两个位置 i i i和 j j j,交换 s i s_i si和 s j s_j sj
问,能否使得给出的字符串小于该字符串反转之后的结果.
分析
只有当该字符串本身仅包含一个字符或没有操作次数时可能无法完成,其他情况下均可满足题意.
代码
#include<bits/stdc++.h>
using namespace std;
void init() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
}
void solve() {
int n, k;
cin >> n >> k;
string s;
cin >> s;
string str = s;
reverse(str.begin(), str.end());
if (str > s) {
cout << "YES" << endl;
return;
}
if (str <= s && k == 0) {
cout << "NO" << endl;
return;
}
for (int i = 1; i < s.length(); i++) {
if (s[i] != s[0]) {
cout << "YES" << endl;
return;
}
}
cout << "NO" << endl;
}
int main() {
init();
int T = 1;
cin >> T;
while (T--){
solve();
}
return 0;
}
B.Serval and Final MEX(思维)
题意
给出一个包含 n n n个数字的数组 a a a,你需要进行若干次操作后使得数组 a a a仅包含一个数字 0 0 0.
具体操作为:
- 选择一个区间 [ l , r ] [l, r] [l,r],将该区间的数字删除,并放回一个数字,该数字为 M E X ( a l , … , a r ) MEX(a_l, \ldots, a_r) MEX(al,…,ar)
分析
对于没有 0 0 0的情况,直接一次操作 1 , n 1, n 1,n即可.
对于包含一个 0 0 0的情况,任选 0 0 0左边一个数字或右边一个数字,先消除 0 0 0,再消除整个区间即可.
对于包含两个以上 0 0 0的情况,可以将数据分成两块,每块均包含至少一个 0 0 0或一边全 0 0 0的两种情况,消除掉 0 0 0后合并区间即可.
代码
#include<bits/stdc++.h>
using namespace std;
void init() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
}
int n, a[5005];
void solve() {
cin >> n;
int l = -1, r = -1;
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (l == -1 && a[i] == 0) l = i;
if (a[i] == 0) r = i;
}
if (l == -1) {
cout << "1" << endl << 1 << ' ' << n << endl;
return;
}
if (l == r) {
cout << 2 << endl;
if (l == n) {
cout << 2 << ' ' << n << endl;
cout << 1 << ' ' << 2 << endl;
} else {
cout << 1 << ' ' << n - 1 << endl;
cout << 1 << ' ' << 2 << endl;
}
} else {
if (l == 1) {
if (r == 2) {
cout << 2 << endl;
cout << 1 << ' ' << 2 << endl;
cout << 1 << ' ' << n - 1 << endl;
return;
}
cout << 3 << endl;
cout << 1 << ' ' << 2 << endl;
cout << 2 << ' ' << n - 1 << endl;
cout << 1 << ' ' << 2 << endl;
return;
}
if (r == n) {
cout << 2 << endl;
cout << l << ' ' << n << endl;
cout << 1 << ' ' << l << endl;
return;
}
cout << 3 << endl;
cout << l + 1 << ' ' << n << endl;
cout << 1 << ' ' << l << endl;
cout << 1 << ' ' << 2 << endl;
}
}
int main() {
init();
int T = 1;
cin >> T;
while (T--){
solve();
}
return 0;
}
C.Serval and The Formula(思维)
题意
给出两个数字 x , y x, y x,y,请你求出一个数字 k k k,使得 ( x + k ) + ( y + k ) = ( x + k ) ⊕ ( y + k ) (x + k) + (y + k) = (x + k) \oplus (y + k) (x+k)+(y+k)=(x+k)⊕(y+k)
如果不存在满足要求的 k k k,输出 − 1 -1 −1
思路
仅当 x = y x = y x=y时无解.
想要使得 ( x + k ) + ( y + k ) = ( x + k ) ⊕ ( y + k ) (x + k) + (y + k) = (x + k) \oplus (y + k) (x+k)+(y+k)=(x+k)⊕(y+k),不难想到可以使得 x , y x, y x,y中较大的数进位变为 2 i 2^{i} 2i的形式,由于操作的是较大数,那么较小数加完后仍然是小于较大数的,而 2 i 2^{i} 2i的二进制仅最高位为 1 1 1,那么与较小数异或的结果和加法的结果必然是相同的.
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void init() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
}
int n;
void solve() {
ll x, y;
cin >> x >> y;
if (x == y) {
cout << -1 << endl;
} else {
ll num = log2(max(x, y)) + 1;
ll ans = 1ll << num;
ans -= max(x, y);
cout << ans << endl;
}
}
int main() {
init();
int T = 1;
cin >> T;
while (T--){
solve();
}
return 0;
}
D.Serval and Kaitenzushi Buffet(贪心)
题意
给出 n n n个盘子,每个盘子上有一个美味值 d i d_i di以及 k k k个寿司,第 i i i回合可以执行以下三种操作之一:
-
拿第 i i i个盘子,此时面前的寿司数量增加 k k k,获得 d i d_i di美味值
-
吃掉一个寿司
-
什么也不做
问:如果要求结束 n n n回合后,面前不允许还剩有寿司,最大能获得的美味值是多少?
分析
不难想到,从前往后很难决策当前的寿司盘子是否要拿,因此,可以反过来想,对于从后往前的第 k + 1 ∼ 2 × k + 1 k + 1 \sim 2 \times k + 1 k+1∼2×k+1个盘子,我们只能选择一个,因为哪怕拿的是倒数 2 × k + 1 , 2 × k 2 \times k + 1, 2 \times k 2×k+1,2×k这两个盘子,拿需要 2 2 2回合,吃需要 2 × k 2 \times k 2×k回合,总共需 2 × k + 2 2 \times k + 2 2×k+2回合,总时间是不够的,然后继续考虑 2 × k + 2 ∼ 3 × k + 2 2 \times k + 2 \sim 3 \times k + 2 2×k+2∼3×k+2,这里能选的就是两个盘子,但是如果所有的寿司美味值不如后面的部分,那么保留的还是后面已经取的盘子,因此,可以从后往前维护一个优先队列,优先队列的大小由当前剩余回合决定,超出的部分直接丢弃,结束后,优先队列剩余的数字之和就是要求的答案.
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
void init() {
ios::sync_with_stdio(false);
cin.tie(nullptr); cout.tie(nullptr);
}
int n, k;
ll a[200005];
void solve(){
cin >> n >> k;
for (int i = n; i >= 1; i--) cin >> a[i];
priority_queue<ll, vector<ll>, greater<ll> > Q;
for (int i = k + 1; i <= n; i++) {
Q.push(a[i]);
while (Q.size() > i / (k + 1)) {
Q.pop();
}
}
ll ans = 0;
while (!Q.empty()) {
ans += Q.top();
Q.pop();
}
cout << ans << endl;
}
int main() {
init();
int T = 1;
cin >> T;
while (T--){
solve();
}
return 0;
}