A. Setting up Camp
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
void solve() {
int a, b, c;
cin >> a >> b >> c;
int res = a + b / 3;
b %= 3;
if (b != 0) {
if (c < 3 - b) {
cout << "-1\n";
return;
}
c -= 3 - b, res++;
}
res += ( c + 2 ) / 3 ;
cout << res << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int TC;
for (cin >> TC; TC; TC--) solve();
return 0;
}
B. Fireworks
计算出每种烟花同时最多看多少个,然后相加即可。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
void solve() {
i64 a, b, c;
cin >> a >> b >> c , c ++;
a = ( c + a - 1 ) / a;
b = ( c + b - 1 ) / b;
cout << a + b << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int TC;
for (cin >> TC; TC; TC--) solve();
return 0;
}
C. Left and Right Houses
可以直接枚举一下路的位置,然后后缀和处理一下。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
void solve() {
int n;
string s;
cin >> n >> s;
int l = 0, r = 0, ans;
double p = 1e9;
for (auto i: s) r += i == '1';
for (int i = 0; i <= n; i++) {
if (l >= (i + 1) / 2 and r >= (n - i + 1) / 2) {
double t = abs(0.5 * n - i);
if (p > t) p = t, ans = i;
}
if( i < n ) l += s[i] == '0' , r-= s[i] == '1';
}
cout << ans << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int TC;
for (cin >> TC; TC; TC--) solve();
return 0;
}
D. Seraphim the Owl
首先我们要从前\(m\)个位置选择一个点作为终点,然后从起点到终点的过程中每个点可以任意选\(a,b\)但是终点只能是\(a\)。
为什么过程中可以任意选\(a,b\),对于每个点,如果你直接走过去就是\(b\),如果停留一下就是\(a\)。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
using vi = vector<i64>;
const i64 inf = 1e18;
void solve() {
int n, m;
cin >> n >> m;
vi a(n + 1), b(n + 2);
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
cin >> b[i], b[i] = min(b[i], a[i]);
for (int i = n - 1; i >= 1; i--)
b[i] += b[i + 1];
i64 res = inf;
for (int i = 1; i <= m; i++)
res = min(res, a[i] + b[i + 1]);
cout << res << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int TC;
for (cin >> TC; TC; TC--) solve();
return 0;
}
E. Binary Search
我感觉是可以只通过一次操作就一定可以实现要求。
根据这个猜想,交换的一个点应该是目标数字,所以我枚举另一个点,然后进行交换,最后再模仿题目的二分进行一次 check
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using ui64 = uint64_t;
#define int long long
using vi = vector<int>;
using pii = pair<int, int>;
const int mod = 998244353;
const int inf = 1e18;
const vi dx = {0, 0, 1, -1, 1, 1, -1, -1}, dy = {1, -1, 0, 0, 1, -1, 1, -1};
void solve() {
int n, x;
cin >> n >> x;
vi p(n + 1);
int y;
for (int i = 1; i <= n; i++) {
cin >> p[i];
if (p[i] == x) y = i;
}
for (int i = 1, l, r; i <= n; i++) {
swap(p[i], p[y]);
l = 1, r = n + 1;
for (int m; r - l != 1;) {
m = (l + r) / 2;
if (p[m] <= x) l = m;
else r = m;
}
if (p[l] == x) {
cout << "1\n" << y << " " << i << "\n";
return;
}
swap(p[i], p[y]);
}
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
F. Kirill and Mushrooms
强度等于\(k\times val\),其中\(k\)是我选择的个数,\(val\)是选择的最小值。
如果我枚举出\(k\)就可以确定那些蘑菇的值为 0,然后在剩下的蘑菇中贪心的选择最大的\(k\)个,这样就可以知道\(val\)
我用multiset<int>
维护两个集合,一个是cnt
表示当前不为0 且没有被选到的蘑菇,q
是当前被选到的最大的\(k\)个蘑菇。
然后从小到大枚举\(k\),每次都从\(cnt\)中取最大值填入到q
中,直到q.size() == k
。然后随着选择数量增大,就要是的一些蘑菇变为0,也就说要从两个集合中删掉一些蘑菇,每次删除时优先从cnt
中删除即可。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = long long;
using ui64 = uint64_t;
#define int long long
using vi = vector<int>;
using pii = pair<int, int>;
const int mod = 998244353;
const int inf = 1e18;
void solve() {
int n;
cin >> n;
multiset<int> cnt, q;
vi a(n + 1);
vi p(n + 1);
for (int i = 1; i <= n; i++)
cin >> a[i], q.insert(a[i]);
for (int i = 1; i <= n; i++)
cin >> p[i];
int res = -inf, val = -inf;
for (int i = 1, v, x; i <= n; i++) {
while (not q.empty() and cnt.size() < i) {
x = *q.rbegin();
cnt.insert(x), q.erase(q.find(x));
}
if (cnt.size() < i) break;
v = *cnt.begin() * i;
if (v > res) res = v, val = i;
if (q.count(a[p[i]]))
q.erase(q.find(a[p[i]]));
else
cnt.erase(cnt.find(a[p[i]]));
}
cout << res << " " << val << "\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int t;
cin >> t;
while (t--)
solve();
return 0;
}
G. Cook and Porridge
这个题目实际上要求维护一个序列,但是这个序列要实现一个插队的功能。
如果把重新入队的人单独放在一个优先队列内。然后提前维护一个\(k_i\)的后缀最大值\(suf_i\)
如果没时刻我取出队列的第一个和优先队列中的第一个。然后比较一下后缀最值和优先队列队首权值的大小,如果后缀最值更大说明不会插队到当前的人前面,则队首出队,否则优先队列出队。
#include <bits/stdc++.h>
using namespace std;
using i32 = int32_t;
using i64 = int64_t;
using vi = vector<i64>;
using pii = pair<i64, i64>;
const i64 inf = 1e18;
#define int i64
void solve() {
int n, d;
cin >> n >> d;
vector<pii> a(n);
for (auto &[k, s]: a) cin >> k >> s;
vi suf(n + 1);
for (int i = n - 1; i >= 0; i--)
suf[i] = max(a[i].first, suf[i + 1]);
vector<vi> que(d + 1);
int t = 0;
set<array<int, 4>> st;
for (int time = 1; time <= d; time++) {
if (not st.empty() and prev(st.end())->at(0) > suf[t]) {
auto [k, tim, s, id] = *prev(st.end());
s = -s;
st.erase(prev(st.end()));
if (time + s <= d)
que[time + s].push_back(id);
} else {
auto [kt, st] = a[t];
if (time + st <= d)
que[time + st].push_back(t);
t++;
}
if (t == n) {
cout << time << "\n";
return;
}
for (auto id: que[time]) {
auto [ki, si] = a[id];
st.insert({ki, -time, -si, id});
}
}
cout << "-1\n";
return;
}
i32 main() {
ios::sync_with_stdio(false), cin.tie(nullptr);
int TC;
for (cin >> TC; TC; TC--) solve();
return 0;
}
标签:int,vi,Codeforces,i64,solve,using,Div,TC,935
From: https://www.cnblogs.com/PHarr/p/18088311