AtCoder Beginner Contest 250 G,H
G
法1:
我们有一种显然的贪心思路——对于一个\(i\),尝试找到后面一个\(j\),满足\(P_{j}>P_{i}\),在\(i\)时刻买入,在\(j\)时刻卖出。
这样的做法显然不对。
假设我们是在\(i\)时买入一个stonk,在\(j\)时卖出,而在\(k\)时卖出是最优解。那么我们可以假设在\(j\)时刻卖出后,我们立刻以\(j\)的价格“尝试”买入,然后在\(k\)时刻,发现前面有\(j\)时刻的stonk,则总价值为\(p_{j}-p_{i}+p_{k}-p_{j}\),那么和\(i\)时买入\(k\)时卖出是没有差异的。
我们使用堆去维护,对于\(i\)从\(1\)到\(n\),我们找到堆中最小的元素,如果它小于\(p_{i}\),那么我们暂且卖出它,并将\(p_{i}\)加入队列中。最后,我们还需要把\(p_{i}\)本身加入。
法2:
假设\(a_{i}=1\)表示我们在\(i\)时刻买入stonk,\(a_{i}=-1\)表示我们在\(i\)时刻卖出stonk,\(a_{i}=0\)表示我们什么都不做。
那么我们的前缀和\(sum_{i}=\sum_{j=0}^{i} a_{j}\)必须要满足\(sum_{i}>0\)。
开始我们假设所有点都是\(a_{i}=1\)。
从大往小考虑\(p_{i}\):若我们选择在\(i\)时刻卖出,那么\(sum_{i},sum_{i+1},...\)都要减去\(2\);若我们在\(i\)时刻什么都不做,那么\(sum_{i},sum_{i+1},...\)都要减去\(1\);否则维持原样,\(sum_{i}\)也不改变。
我们肯定尽可能将更多的点改为\(-1\),其次是\(0\)。所以对于\(\min_{j=i}^{n} sum_{j}\geq 2\)时,我们肯定选择在\(i\)时刻卖出;对于\(\min_{j=i}^{n} sum_{j}=1\)时,我们选择什么都不做;否则我们选择维持原样。
这可以使用线段树实现。
H
注意到出发和到达点都是house,那么我们大致的路线就是从\(x\)出发,到达另一个house,从那个house再到其它的house,直到到达终点。
我们要对题中输入的每一条边\((x,y)\),分别找到离\(x,y\)最近的house(这可以使用Dijkstra解决),设为\(x',y'\),这样从\(x'\)到\(y'\),可以经过边\(x',y'\),且代价为\(dis(x',x)+dis(x,y)+dis(y,y')\)。这样我们就组成了一个新的图。
举个例子,样例中建出的新图,有三个点\(V=\{1,2,3\}\),有两条边\(E=\{(1,2,15),(2,3,5)\}\)。
如果我们定义新图中一条路径的价值为经过边权的最大值(即Takahashi至少要保存清醒的时间)。那么对于询问,我们就是查询新图中连接它们所有路径中价值最小的那个。
法1:
我们将询问离线。从小到大加入新图中的边,使用并查集查询在\(t_{i}\)时刻,\(x_{i},y_{i}\)是否在同一个联通块中。
法2:
在线解决。不难发现价值最小的那个路径一定在最小生成树中,因为Kruskal的过程就是从小到大依次加边(用权值最小的边合并两个连通块),遇到环就不加入,故在生成的树中的路径一定是最大值最小的。
所以,对于从\(x_{i}\)到\(y_{i}\),我们可以放到生成树中,倍增解决,找到所需的最小代价,和\(t_{i}\)比较大小即可。
浙公网安备 33010602011771号