2017.07.13【NOIP提高组】模拟赛B组

T2:

设f[i]表示当前第i个人认识的最右边的人的编号。

50分做法:

每次枚举l,r之间的i,当f[i]<r时ans=ans+r-f[i],然后把f[i]更新为r。

初始值:f[i]=i


100分做法:

我们发现f[i]是递增的,所以我们考虑用线段树维护f[i]。

设f1[]表示区间的最大值,f2[]表示区间的最小值,f3[]表示区间的和。

我们每次要找出一个s,使得l<=s<=r且f[s]<r且s最大,那么ans=(s-l+1)*r-sum(f[l~s]),这个式子由50分的式子得到。

求sum的一步可以用区间查询来完成,在做完这一步之后我们要把f[l~s]的值赋为r,这一步可以用区间修改来完成,关键是怎样求s。

我们可以用f1,f2来求s,我们每一次从线段树的根节点开始往下走,直到走到一个叶节点,这个叶节点就是答案,下面说说怎样走。

假设当前的左子树是l,右子树是r,要查找的值为w,那么

若f1[l]>=w,则往左走

else 若f2[r]>=w,则往左走

        else 往右走


T3:设f[i][0/1]表示第i个位置是直接(0)还是间接(1)下载的。

那么f[i][0]=min(f[i+1][0],f[i+1][1])+c[i],f[i+1][1]=min(f[j][0]+(j-i+1)*(j-i)/2)。

这是O(n^2)的算法,只有60分,所以我们要优化。

我们发现,若当前有j<k且f[j][0]<=f[k][0],那么j一定比k优,所以我们可以用一个单调栈对f[i][0]进行维护。我们每一次都将f[i][0]入栈,把栈中<=f[i][0]的元素都弹掉,那么每次计算f[i][1]的时候只需枚举栈中的元素就可以了。这样可以得80分。

100分只需在这个基础上加一个小小的优化,每次枚举栈时要从上往下枚举,若当前的栈中元素的转移所需的费用((j-i+1)*(j-i)/2)已经不小于f[i][1]了,那么就break。这样就可以AC了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值