Codeforces Round 963 (Div. 2)
链接:https://codeforces.com/contest/1993
A. Question Marks
题目:
解题思路:
签到题,记录ABCD四个字符出现的次数,然后跟n比较取较小值累加一下就行了
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
void solve() {
ll n; cin >> n;
string s; cin >> s;
map<char, ll> m;
for (ll i = 0; i < s.size(); i++) {
if (m[s[i]]) m[s[i]]++;
else m[s[i]] = 1;
}
ll ans = 0;
ans += min(m['A'], n);
ans += min(m['B'], n);
ans += min(m['C'], n);
ans += min(m['D'], n);
cout << ans << '\n';
}
int main () {
ios_base::sync_with_stdio(0); cin.tie(0);cout.tie(0);
int t; cin >> t;
while (t--) {
solve();
}
return 0;
}
B. Parity and Sum
题目:
解题思路:
模拟,遍历记录每个元素的奇偶性,全奇或全偶输出0;否则将偶数与奇数相加变为奇,记录相加次数。
注意:
可能相加的奇数小于偶数,这样值变的是奇数的值,如果出现这种情况需先将奇数与最大的偶数相加,使得最后变的都是偶数,次数需加一
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
void solve() {
ll n; cin >> n;
vector<ll> a(n), E;
ll odd = 0, even = 0;
ll max_odd = 0;
ll ans = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
if (a[i] % 2 == 1) {
odd++;
if (a[i] > max_odd)
max_odd = a[i];
} else {
even++;
E.push_back(a[i]);
}
}
//全为奇数或全为偶数
if (!odd || !even) {
cout << ans << '\n';
return;
}
ans += even;
sort(E.begin(), E.end());
for (int i = 0; i < E.size(); i++) {
if (max_odd < E[i]) {
ans++;
break;
}
max_odd += E[i];
}
cout << ans << '\n';
}
int main () {
ios_base::sync_with_stdio(0); cin.tie(0);cout.tie(0);
int t; cin >> t;
while (t--) {
solve();
}
return 0;
}
C. Light Switches
题目:
解题思路:
显然,只有当最后(晚)一个灯亮了才可能所有都亮灯,然后因为每个灯都隔k分钟亮灭亮灭,那么他们的变化周期最多为k,那么我们只要模拟一下最后一个灯亮的第一个周期就能判断是否所有灯都亮灯了,如果亮灯,那么最先满足条件的时间就是答案
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
void solve() {
ll n, k; cin >> n >> k;
vector<ll> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
sort(a.begin(), a.end());
ll temp = a[n-1];
ll flag = 0;
for (int i = 0; i < n-1; i++) {
//通过周期k判断第i个灯是否亮
if ((temp - a[i]) / k % 2 == 1) {
temp++;
i = -1;
}
//如果时间超过最后一个灯的第一个亮灯周期
if (temp >= a[n-1] + k) {
flag = 1;
break;
}
}
if (flag) {
cout << -1 << '\n';
} else {
cout << temp << '\n';
}
}
int main () {
ios_base::sync_with_stdio(0); cin.tie(0);cout.tie(0);
int t; cin >> t;
while (t--) {
solve();
}
return 0;
}
D. Med-imize
题目:
解题思路:
二分加dp,先二分答案,然后将二分的mid作为中位数med,先构建一个b数组来记录a数组中每个数对于med的大小比较情况,接着构建一个dp数组,找出最后删完元素后最多大于等于med的数量,具体怎么dp见代码注释
PS:
可能注释也还是不怎么清楚,但我尽力了
代码:
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define nl '\n'
const ll N = 500009;
ll n, k;
ll dp[N], a[N], b[N];
bool check(ll med) {
for (ll i = 0; i < n; i++) { //构造数组b[],记录a[]值与med比较的的结果
if (a[i] >= med) { //因为med = ⌊(n+1)/2⌋, 所以 = 视为 >
b[i] = 1;
} else {
b[i] = -1;
}
}
dp[0] = b[0]; //初始化第一个值
for (ll i = 1; i < n; i++) {
if (i % k == 0) { //i % k == 0时,说明当前长度恰为k+1,需要删除长度为k的子数组
dp[i] = __max(dp[i-k], b[i]); //dp[i-k]是保留第一个元素的情况,b[i]是保留最后一个元素的情况
} else {
dp[i] = dp[i-1] + b[i]; //对于每个dp[i]都已经是在当前k区间范围内dp优化过的值了
if (i > k) //如果i>k,当前子数组可能不是最优的情况,用__max函数进行比较优化,使得b[]的和尽可能的大
dp[i] = __max(dp[i], dp[i-k]); //判断较上一个i%k的位置加k后是否更优,相当于对于每一个dp[i%k]取最优
}
}
return dp[n-1] > 0;
}
void solve() {
cin >> n >> k;
for (ll i = 0; i < n; i++) cin >> a[i];
ll l = 1, r = 1e9; //二分,判断所有可能为med的值, (1 ≤ a[i] ≤ 10^9)
while (l <= r) {
ll mid = (l + r) >> 1;
if (check(mid)) { //如果返回为true,则当前值小于等于最终答案
l = mid + 1;
} else {
r = mid - 1;
}
}
cout << r << nl; //最后退出时肯定是因为true成立,使得l=mid+1导致l > r, 上一个应为l = r = mid,故答案为r
}
int main () {
ios_base::sync_with_stdio(0); cin.tie(0);cout.tie(0);
ll t; cin >> t;
while (t--) {
solve();
}
return 0;
}