VP Educational Codeforces Round 30
A. Chores
点击查看代码
void solve() {
int n, k, x;
std::cin >> n >> k >> x;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
int ans = k * x;
for (int i = 0; i < n - k; ++ i) {
ans += a[i];
}
std::cout << ans << "\n";
}
B. Balanced Substring
题意:求一个\(01\)串最长的\(0\)和\(1\)个数相同的子串。
\(1\)的位置加一,\(0\)的位置减一,记录相同的前缀和。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::string s;
std::cin >> s;
std::vector<int> sum(n + 1);
for (int i = 0; i < n; ++ i) {
sum[i + 1] = sum[i] + (s[i] == '1' ? 1 : -1);
}
std::map<int, int> mp;
int ans = 0;
mp[0] = 0;
for (int i = 1; i <= n; ++ i) {
if (mp.count(sum[i])) {
ans = std::max(ans, i - mp[sum[i]]);
} else {
mp[sum[i]] = i;
}
}
std::cout << ans << "\n";
}
C. Strange Game On Matrix
题意:每一列删去最顶上的若干个一,然后从剩下的最高的一往下数最多\(k\)个,使得和最大已经修改的数最少。
模拟题,每一列搞个前缀和,然后枚举选中的第一个一。
点击查看代码
void solve() {
int n, m, k;
std::cin >> n >> m >> k;
std::vector a(n + 1, std::vector<int>(m + 1));
std::vector sum(n + 1, std::vector<int>(m + 1));
for (int i = 1; i <= n; ++ i) {
for (int j = 1; j <= m; ++ j) {
std::cin >> a[i][j];
sum[i][j] = sum[i - 1][j] + a[i][j];
}
}
int ans = 0, cnt = 0;
for (int j = 1; j <= m; ++ j) {
int max = 0, del = 0;
for (int i = 1; i <= n; ++ i) {
if (a[i][j] == 1) {
int x = std::min(n, i + k - 1);
if (sum[x][j] - sum[i - 1][j] > max) {
max = sum[x][j] - sum[i - 1][j];
del = sum[i - 1][j];
}
}
}
ans += max;
cnt += del;
}
std::cout << ans << " " << cnt << "\n";
}
D. Merge Sort
题意:对于归并排序,如果当前区间已经有序则返回,否则递归左右子区间。构造一个排列使得调用函数的总次数为\(k\)。
次数总为奇数,因为最开始调用了一次,然后如果要继续递归则两个子区间都会调用一次。
那么我们可以交换\(mid - 1, mid\)这两个位置,这样左右区间依然有序,并且当前区间无序,就可以向下递归。
点击查看代码
void solve() {
int n, k;
std::cin >> n >> k;
std::vector<int> a(n);
std::iota(a.begin(), a.end(), 1);
auto dfs = [&](auto & self, int l, int r) -> void {
if (l + 1 == r || k == 0) {
return;
}
k -= 2;
int mid = l + r >> 1;
std::swap(a[mid - 1], a[mid]);
self(self, l, mid);
self(self, mid, r);
};
k -= 1;
dfs(dfs, 0, n);
if (k == 0) {
for (int i = 0; i < n; ++ i) {
std::cout << a[i] << " \n"[i == n - 1];
}
} else {
std::cout << -1 << "\n";
}
}
E. Awards For Contestants
题意:数组从大到小排序后,把区间分成\(4\)段,第\(4\)段长度可以为\(0\)。要求前三段的长度都互相不超过另外两段的两倍,同时要求第一段最小值减第二段最大值最大,满足上面条件还要第二段最小值减第三段最大值最大,同时要求第三段最小值减第四段最大值最大。
可以枚举前两段,那么第三段可以取的区间范围也可以算出来。然后第三段的结尾我们肯定要减下一个数最大的位置,可以用线段树维护。
注意如果第四段为空,则第三段减第四段的值等于第三段的最小值。
点击查看代码
#define ls (u << 1)
#define rs (u << 1 | 1)
#define umid (tr[u].l + tr[u].r >> 1)
template <class Info>
struct Node {
int l, r;
Info info;
};
template <class Info>
struct SegmentTree {
std::vector<Node<Info> > tr;
SegmentTree(int _n) {
init(_n);
}
SegmentTree(std::vector<Info> & a) {
init(a);
}
void init(int _n) {
tr.assign(_n << 2, {});
build(0, _n - 1);
}
void init(std::vector<Info> & a) {
int _n = (int)a.size();
tr.assign(_n << 2, {});
build(0, _n - 1, a);
}
void pushup(int u) {
tr[u].info = tr[ls].info + tr[rs].info;
}
void build(int l, int r, int u = 1) {
tr[u] = {l, r, {}};
if (l == r) {
return;
}
int mid = l + r >> 1;
build(l, mid, ls); build(mid + 1, r, rs);
}
void build(int l, int r, std::vector<Info> & a, int u = 1) {
tr[u] = {l, r, {}};
if (l == r) {
tr[u].info = a[l];
return;
}
int mid = l + r >> 1;
build(l, mid, a, ls); build(mid + 1, r, a, rs);
pushup(u);
}
void modify(int p, Info add, bool set = false) {
int u = 1;
while (tr[u].l != tr[u].r) {
int mid = umid;
if (p <= mid) {
u = ls;
} else {
u = rs;
}
}
if (set) {
tr[u].info = add;
} else {
tr[u].info = tr[u].info + add;
}
u >>= 1;
while (u) {
pushup(u);
u >>= 1;
}
}
Info query(int l, int r, int u = 1) {
if (l <= tr[u].l && tr[u].r <= r) {
return tr[u].info;
}
int mid = umid;
if (r <= mid) {
return query(l, r, ls);
} else if (l > mid) {
return query(l, r, rs);
}
return query(l, r, ls) + query(l, r, rs);
}
};
struct Info {
int max, p;
};
Info operator + (const Info & a, const Info & b) {
Info res{};
if (a.max >= b.max) {
res = a;
} else {
res = b;
}
return res;
}
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::vector<int> id(n);
std::iota(id.begin(), id.end(), 0);
std::sort(id.begin(), id.end(), [&](int i, int j) {
return a[i] > a[j];
});
SegmentTree<Info> tr(n);
tr.modify(n - 1, Info{a[id[n - 1]], n - 1}, true);
for (int i = n - 2; i >= 0; -- i) {
tr.modify(i, Info{a[id[i]] - a[id[i + 1]], i}, true);
}
int p1 = 0, p2 = 1, p3 = 2;
int max1 = -1, max2 = -1, max3 = -1;
for (int i = 0; i + 2 < n; ++ i) {
for (int j = i + 1; j + 1 < n; ++ j) {
if ((i + 1) > 2 * (j - i) || j - i > 2 * (i + 1)) {
continue;
}
int l = j + (std::max(i + 1, j - i) + 1) / 2, r = std::min(n - 1, j + std::min(i + 1, j - i) * 2);
if (l > r) {
continue;
}
auto [v3, p] = tr.query(l, r);
int v1 = a[id[i]] - a[id[i + 1]], v2 = a[id[j]] - a[id[j + 1]];
if (v1 > max1 || (v1 == max1 && v2 > max2) || (v1 == max1 && v2 == max2 && v3 > max3)) {
max1 = v1;
max2 = v2;
max3 = v3;
p1 = i;
p2 = j;
p3 = p;
}
}
}
std::vector<int> ans(n, -1);
for (int i = 0; i <= p1; ++ i) {
ans[id[i]] = 1;
}
for (int i = p1 + 1; i <= p2; ++ i) {
ans[id[i]] = 2;
}
for (int i = p2 + 1; i <= p3; ++ i) {
ans[id[i]] = 3;
}
for (int i = 0; i < n; ++ i) {
std::cout << ans[i] << " \n"[i == n - 1];
}
}

浙公网安备 33010602011771号