The 2nd Universal Cup. Stage 7: Two Capital
题目 B: Bins and Balls
代码实现:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
#define close ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 2e5 + 10;
void solved() {
int n, k;
cin >> n >> k;
vector<int> arr;
for (int i = 1; i <= n; i++) {
int v;
cin >> v;
arr.push_back(v);
}
int l = 0, r = 2e14 + 10;
while (l <= r) {
int mid = (l + r) >> 1;
int pre = 0;
for (int i = 0; i < n; i++) {
if (arr[i] >= mid) {
pre += mid;
} else {
pre += arr[i];
}
}
if (pre / k >= mid) {
l = mid + 1;
} else {
r = mid - 1;
}
}
cout << r << endl;
}
signed main() {
close;
solved();
return 0;
}
题目分析:
这是一道思维题目,可以通过二分答案解决。答案的最小值为0,最大值则可以推导为 (2e14) 左右。要判断当前中间值是否符合要求,需要遍历数组,计算每个数值对中间值的贡献(取最小值)。通过二分法逐步逼近最终答案。
题目 G: Lake
代码实现:
#include <bits/stdc++.h>
using namespace std;
#define int long long int
signed main() {
int n, m;
cin >> n >> m;
int ans = 0;
while (n > 0 || m > 0) {
if (n >= 3 && m >= 3) {
n -= 3;
m -= 3;
if (n > m) {
--n;
} else {
--m;
}
} else if (n >= 3) {
m = 0;
n -= 4;
} else if (m >= 3) {
m -= 4;
n = 0;
} else {
m = 0;
n = 0;
}
++ans;
}
cout << 2*ans-1 << endl;
return 0;
}
题目分析:
这道题的核心是模拟,判断每次如何调整两个变量 n 和 m。每次根据两者的值作出决策,逐步减少它们的值,最终求得答案。
题目 J:Range Sets
代码实现:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define close ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 1e5 + 10;
int tot, rt;
int n, q;
struct SMT
{
int ls, rs;
int v;
} seg[N * 40];
struct Node
{
int l, r;
mutable int val;
Node(int _l, int _r, int _val) : l(_l), r(_r), val(_val) {}
bool operator<(const Node &other) const
{
return l < other.l;
}
};
typedef set<Node>::iterator S_IT;
inline void modify(int &id, int l, int r, int ql, int qr, int v)
{
if (!id)
{
id = ++tot;
}
if (ql <= l && r <= qr)
{
seg[id].v += v;
return;
}
int mid = (l + r) >> 1;
if (ql <= mid)
{
modify(seg[id].ls, l, mid, ql, qr, v);
}
if (qr > mid)
{
modify(seg[id].rs, mid + 1, r, ql, qr, v);
}
}
inline int query(int id, int l, int r, int pos)
{
if (!id)
return 0;
int mid = (l + r) >> 1;
if (pos <= mid)
{
return query(seg[id].ls, l, mid, pos) + seg[id].v;
}
else
{
return query(seg[id].rs, mid + 1, r, pos) + seg[id].v;
}
}
struct ODT
{
set<Node> s;
S_IT split(int pos)
{
auto it = s.lower_bound(Node(pos, 0, 0));
if (it != s.end() && it->l == pos)
return it;
if (it == s.begin())
return s.end();
--it;
int l = it->l, r = it->r;
int v = it->val;
s.erase(it);
s.insert(Node(l, pos - 1, v));
return s.insert(Node(pos, r, v)).first;
}
inline void assign(int L, int R, int v)
{
S_IT itr = split(R + 1), itl = split(L);
for (S_IT it = itl; it != s.end() && it->l <= R;)
{
if (it->val != v)
{
modify(rt, 1, n, it->l, it->r, v - it->val);
}
it = s.erase(it);
}
s.insert(Node(L, R, v));
}
} tr[N * 40];
void solved()
{
cin >> n >> q;
unordered_map<int, int> mp;
while (q--)
{
char op;
cin >> op;
if (op == '?')
{
int pos;
cin >> pos;
cout << query(rt, 1, n, pos) << endl;
}
else if (op == '-')
{
int l, r, x;
cin >> l >> r >> x;
if (!mp.count(x))
{
mp[x] = ++tot;
tr[mp[x]].s.insert(Node(1, n, 0));
}
tr[mp[x]].assign(l, r, 0);
}
else
{
int l, r, x;
cin >> l >> r >> x;
if (!mp.count(x))
{
mp[x] = ++tot;
tr[mp[x]].s.insert(Node(1, n, 0));
}
tr[mp[x]].assign(l, r, 1);
}
}
}
signed main()
{
close;
solved();
return 0;
}
题目分析:
这是一道数据结构题目,涉及动态开点线段树的操作。通过使用线段树,我们可以高效处理区间修改和单点查询操作。这种数据结构可以用于优化时间复杂度,在面对较大的数据范围时尤为实用。后续会更新更详细的讲解。
题目 K: Integer Half-Sum
代码实现:
#include <bits/stdc++.h>
using namespace std;
#define int long long int
#define close ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
signed main() {
close;
int l, r;
cin >> l >> r;
if (l == r)
cout << l << endl;
else if (l == r - 1)
cout << -1 << endl;
else
cout << r - 1 << endl;
return 0;
}
题目分析:
考虑 (l) 和 (r) 的情况,如果两个数相邻,那么一定是一个奇数,一个偶数,结果为 -1;如果两个数相等 (l == r),则答案为 (l);如果这两个数中间至少隔了一个数,则可以继续操作(三个一组)直到得到答案。
题目 H: Forbidden Set
代码实现:
#include <bits/stdc++.h>
using namespace std;
#define int long long int
#define close ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
const int N = 5e6;
vector<int> pri;
bool not_prime[N];
void pre(int n) {
for (int i = 2; i <= n; ++i) {
if (!not_prime[i])
pri.push_back(i);
for (int pri_j : pri) {
if (i * pri_j > n)
break;
not_prime[i * pri_j] = true;
if (i % pri_j == 0)
break;
}
}
}
signed main() {
close;
int ans = -1;
int n;
cin >> n;
pre(2000);
vector<bool> s(11);
for (int i = 1; i <= n; i++) {
int x;
cin >> x;
s[x] = true;
}
for (auto i : pri) {
bool f = false;
int t = i;
while (t) {
int a = t % 10;
t /= 10;
if (s[a]) {
f = true;
break;
}
}
if (!f) {
ans = i;
break;
}
}
cout << ans << endl;
return 0;
}
题目分析:
这道题通过对素数的处理,寻找符合条件的数。我们预处理 2000 以内的素数,并进行枚举,检查是否存在禁止的数字。通过这种方式,我们可以有效地找到符合条件的最小素数。