题解:P17716 [HexOI Round 1] 变魔术 / magic

· · 题解

思路

题目允许随意给淘汰的积木分堆,因为是淘汰小的,那显然把要扔掉的积木全部拆成单块(大小为 1) 对我们最有利。此时我们保留的这一堆,只要权值和大于等于被淘汰积木里的最大值就行。

所以想让某个积木活到最后,比它小的积木都无所谓,真正的阻碍只有那些比它大的积木。我们需要把比它大的积木踢出局。

把积木按美丽度升序排序:a_1 \le a_2 \le \dots \le a_n,前缀和记为 \mathit{pref}[i] = \sum_{j=1}^i a_j。

考虑怎么踢掉排在后面的大积木 a_k:

要想战胜 a_k,最赚的做法肯定是把排在它前面的所有积木全部拉过来抱团,此时能凑出的最大战力就是 \mathit{pref}[k-1]。

因此,只要一个积木后面存在任何一个不可能被顶掉的大积木,它就必死无疑。

我们只需要线性扫一遍,找到最后一个顶不掉的积木的位置(即最大的满足 \mathit{pref}[k-1] < a_k 的 k):

若全程都不存在这样的断点,说明所有人都能通关。

复杂度分析

代码

::::warning[注意]{open}

:::: ```cpp #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=100005; int n; ll pref[N]; int ans[N]; struct Block{ int id; ll val; bool operator<(const Block&other)const{ return val<other.val; } //重载运算符 < }a[N]; int main(){ ios::sync_with_stdio(false); cin.tie(nullptr); cin>>n; for(int i=1;i<=n;i++) cin>>a[i].val,a[i].id=i; sort(a+1,a+n+1); for(int i=1;i<=n;i++) pref[i]=pref[i-1]+a[i].val; int fail=1; for(int i=2;i<=n;i++) if(pref[i-1]<a[i].val) fail=i; for(int i=fail;i<=n;i++) ans[a[i].id]=1; for (int i=1;i<=n;i++) cout<<ans[i]<<' '; return 0; } ```