vp Educational Codeforces Round 168 (Rated for Div. 2) A - E

link

A C D,怎么没过 B?我靠,崩溃了牢弟 qwq


A - Strong Password

B - Make Three Regions

这题。。。我居然用 a[2][j] 然后还真只开了 a[2][N] 的大小,结果 cf test 1 多测只输出一个结果,没见过啊,这直接给我干蒙了啊,又是没有调出来,数组空间开小了这种低级错误也能犯

C - Even Positions

一开始以为很不可做,之前是看到字符串匹配之类的就头疼,

不过最后十分钟又看了一下,发现就是简单贪心,总是选择较近的空位配对,两个方向扫一遍,最后三分钟 A 掉了

D - Maximize the Root

树上贪心,(dp?倒是不至于,就是简单的 dfs 加分讨

一种很显然的贪心是,对于一个子树(根节点非叶节点),总是让它的所有点权趋于平均,但是保证子树的根节点比子树中的其他节点的最小值严格不小,这样在向上回溯时能保证非直接儿子不会非法(即点权减小为负数)

对子树跟节点点权 au,直接儿子中点权最小值 av 分类讨论

  • auav,只能直接 au=av

  • au=av1,这种平均状态是标准的,不用改变

  • au<av,要使之趋于平均,au=au+avau2,这样就达到要么 au=av,要么 au=av1 的效果

当然,根节点是特殊情况,因为它不需要考虑父节点,所以直接 au=au+av

复杂度 O(n)

code
#include <bits/stdc++.h>
#define re register int
#define int long long
using namespace std;
const int N = 2e5 + 10, inf = 1e9 + 10;
struct Edge
{
int to, next;
}e[N << 1];
int idx, h[N];
int T, n, a[N], in[N];
inline void add(int x, int y)
{
e[++ idx] = (Edge){y, h[x]};
h[x] = idx;
}
void dfs(int u, int fa)
{
int sum = 0, min_son = inf;
for (re i = h[u]; i; i = e[i].next)
{
int v = e[i].to;
if (v == fa) continue;
dfs(v, u);
min_son = min(min_son, a[v]); // 注意是比较更新过后的权值
// sum += a[v];
}
if (u == 1)
{
// cout << "check " << min_son << '\n';
a[u] += min_son;
return;
}
else if (in[u] > 1)
{
if (a[u] >= min_son) a[u] = min_son;
else if (a[u] == min_son - 1) a[u] = a[u];
else
a[u] += floor((double)((min_son - a[u]) / 2));
}
else return;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> T;
while (T --)
{
memset(h, 0, sizeof(h)); idx = 0;
memset(in, 0, sizeof(in));
cin >> n;
for (re i = 1; i <= n; i ++) cin >> a[i];
for (re i = 2; i <= n; i ++)
{
int x; cin >> x;
add(x, i), add(i, x);
in[x] ++, in[i] ++;
}
dfs(1, 0);
// cout << a[3] << '\n';
cout << a[1] << '\n';
}
return 0;
}

E - Level Up

一开始我以为是个 dp?但是不会推

发现题目已经将一个求解问题转化为判定问题,那考虑往判定方向思考

对于 k=x,发现 x 越小,对于第 i 个怪兽而言,它越容易逃跑,因为 k 越小,玩家期望升级越快,期望等级越比怪物等级高,反之则越不容易逃跑。。。似乎存在二分性

考虑 二分 k

那我们可以二分一个 k,满足在这个 k 下,第 i 个怪物 刚好不逃跑,这样询问时就转化为简单的判定了

考虑一个怪物刚好不逃跑的充要条件就是玩家等级不大于怪物等级,最小化 k

那么玩家到达第 i 个位置,至少之前要打过 aik 个怪兽,即升了 ai 级变为 ai+1>ai,这样怪兽就刚好逃跑(似乎刚好逃跑更自然想到,反正也一样二分,反过来就可以了

所以,如果之前打过的怪兽数量 queryaik,那么就可以判定怪兽会逃跑

而如何求 query 呢?注意到我们每次二分出来的值的含义是 刚好使该怪兽不会逃跑的 k,即会打该怪兽

那么就很显然了,每次二分完对 k 值域加贡献 1,判定时求个前缀即可,考虑 线段树 简单维护

时间复杂度 O(nlog2n)

code
#include <bits/stdc++.h>
#define re register int
#define lp p << 1
#define rp p << 1 | 1
using namespace std;
typedef long long LL;
const int N = 2e5 + 10;
struct Tree
{
int l, r, sum;
}t[N << 2];
int n, q, a[N], not_run[N];
inline void build(int p, int l, int r)
{
t[p].l = l, t[p].r = r;
if (l == r) return;
int mid = (l + r) >> 1;
build(lp, l, mid);
build(rp, mid + 1, r);
}
inline void update(int p, int x, int k)
{
if (t[p].l == x && t[p].r == x)
{
t[p].sum += k;
return;
}
int mid = (t[p].l + t[p].r) >> 1;
if (x <= mid) update(lp, x, k);
if (x > mid) update(rp, x, k);
t[p].sum = t[lp].sum + t[rp].sum;
}
inline LL query(int p, int l, int r)
{
if (l <= t[p].l && t[p].r <= r) return t[p].sum;
LL res = 0;
int mid = (t[p].l + t[p].r) >> 1;
if (l <= mid) res += query(lp, l, r);
if (r > mid) res += query(rp, l, r);
return res;
}
inline bool check(int x, int k)
{
return (LL)a[x] * k <= query(1, 1, k);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> n >> q;
build(1, 1, n);
for (re i = 1; i <= n; i ++) cin >> a[i];
for (re i = 1; i <= n; i ++)
{
int l = 1, r = n;
while (l < r)
{
int mid = (l + r) >> 1;
if (check(i, mid)) l = mid + 1;
else r = mid;
}
update(1, l, 1);
not_run[i] = l;
}
while (q --)
{
int x, k; cin >> x >> k;
cout << (k < not_run[x] ? "No" : "Yes") << '\n';
}
return 0;
}

F - Chips on a Line

*2700 的 dp?感觉很不可做,溜了溜了 ~

posted @   Zhang_Wenjie  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示