归档 221024 - 221030 | 做题记录
E. Best Cow Fences -221025
https://www.acwing.com/problem/content/104/
有意思的题目。
因为丢在了二分的链接里,我们思考一下究竟是什么具有单调性。
硬要说的话,平均值的大小是有单调性的。对于平均值最大的区间,若其平均值大于 \(x\),明显也会大于 \(x-1\)。
这种形式的「单调性」限制了我们的 check
只能朝一个方向写:给出一个平均值 \(x\),判断是否存在长度 \(\ge L\) 的区间,其平均值大于 \(x\)。
即:
\[\frac{\sum_{i=l}^r A_i}{r-l+1} \ge x
\]
转化为:
\[\begin{aligned}
\sum_{i=l}^r A_i &\ge x\times(r-l+1)
\newline
A_l+A_{l+1}+\cdots+A_r &\ge x + x + \cdots + x
\newline
(A_l-x)+(A_{l+1}-x)+\cdots+(A_r-x) &\ge 0
\newline
\sum_{i=l}^r A_i-x &\ge 0
\end{aligned}
\]
所以对于一次 check
,我们把所有 \(A\) 中的元素减去 \(x\),用滑窗找到最大子段和,判断是否大于等于 \(0\) 即可。
注意这里我们把原本寻找单调性的条件「平均值最大的区间的平均值是否大于 \(x\)」转化为了「是否存在区间的平均值大于 \(x\)」。不难发现,当前者满足时,后者也满足;后者满足时,前者也满足,所以两者等价,这种转化是正确的(中肯的,一针见血的)。
namespace XSC062 {
using ll = long long;
const ll inf = 1e12;
const int maxn = 1e5 + 5;
int n, k;
int q[maxn];
ll l, mid, r, res;
ll a[maxn], p[maxn];
inline ll max(ll x, ll y) {
return x > y ? x : y;
}
inline int check(ll x) {
int h = 1, t = 0;
for (int i = 1; i <= n; ++i) {
p[i] = a[i] - x + p[i - 1];
if (h <= t) {
if (p[i] - p[q[h]] >= 0)
return 1;
}
if (i - k + 1 >= 0) {
while (h <= t && p[i - k + 1] < p[q[t]])
--t;
q[++t] = i - k + 1;
}
}
return 0;
}
int main() {
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; ++i)
scanf("%lld", &a[i]), a[i] *= 1000;
l = -inf, r = inf;
while (l <= r) {
mid = (l + r) >> 1;
if (check(mid)) {
res = mid;
l = mid + 1;
}
else r = mid - 1;
}
printf("%lld", res);
return 0;
}
} // namespace XSC062
F. Lost Cows - 221025
倒序处理序列。
容易发现,\(A_i\) 表示的是删掉 \(i+1\sim n\) 后的 rank
,所以我们随便打个线段树什么的就好了。
namespace XSC062 {
#define lt (p << 1)
#define rt (lt | 1)
using namespace fastIO;
const int maxn = 1e5 + 5;
struct _ { int l, r, u; };
int n;
int a[maxn];
_ t[maxn << 2];
inline void pushup(int p) {
t[p].u = t[lt].u + t[rt].u;
return;
}
void bld(int p, int l, int r) {
t[p].l = l;
t[p].r = r;
if (l == r) {
t[p].u = 1;
return;
}
int mid = (l + r) >> 1;
bld(lt, l, mid);
bld(rt, mid + 1, r);
pushup(p);
return;
}
void add(int p, int x, int v) {
if (t[p].l == t[p].r) {
t[p].u += v;
return;
}
int mid = (t[p].l + t[p].r) >> 1;
if (x <= mid)
add(lt, x, v);
else add(rt, x, v);
pushup(p);
return;
}
int getrank(int p, int k) {
if (t[p].l == t[p].r)
return t[p].l;
if (t[lt].u >= k)
return getrank(lt, k);
return getrank(rt, k - t[lt].u);
}
int main() {
read(n);
for (int i = 2; i <= n; ++i)
read(a[i]);
bld(1, 1, n);
for (int i = n; i > 1; --i) {
a[i] = getrank(1, a[i] + 1);
add(1, a[i], -1);
}
a[1] = getrank(1, 1);
for (int i = 1; i <= n; ++i)
print(a[i], '\n');
return 0;
}
} // namespace XSC062
H. Tree - 221025
首先我们根据题目中的明示猜测需要用到最小生成树。
题意可以转化为:找到一个恰好有 \(\text{need}\) 条白边的最小生成树。
所以要处理的问题就是:怎么让最小生成树包含恰好 \(\text{need}\) 条白边。
首先找单调性。
C. 车站分级
一些鲜花
Yeah↗, I liked↘ it!
—— · EOF · ——
真的什么也不剩啦 😖