[BZOJ3441] 乌鸦喝水

正解复杂度 $ O(n*log2(n)) $,然而我打的是 $ O(n*log2(n)*log2(n)) $的。

50分暴力:

$ O(n*m) $暴力模拟喝水过程,不再赘述。

100分算法:

这中多过程题其实有个套路就是每次找出最先使状态变化的时刻,对于这个题来说就是找出那一个最先被喝到不能喝。

考虑用线段树维护(S-w[i])/a[i]+1即能喝的最多次数,这样就可以每次 $ O(1) $查出来啦。

设x为最小的次数,那么我们便可以先在 $ O(1) $的复杂度内把x的整圈转出来,代码实现如下:

m-=x/t[1].sum;
ans+=x/t[1].sum*t[1].sum;
x%=t[1].sum;

 

之后二分查找它的结束位置(因为中间有可能有不能再喝的)

L=pos+1,R=n;
while(L<R)
{
    int mid=(L+R)>>1;
    if(query(1,pos+1,mid)>=x) R=mid;
    else L=mid+1;
}    

(本算法的复杂度瓶颈就是这里)

但是我们发现,有可能根本没有用完所有的喝水次数,所以要再来一圈:

                if(!pos) m--;
                if(x)
                {
                        L=1,R=n;
                        while(L<R)
                        {
                                int mid=(L+R)>>1;
                                if(query(1,pos+1,mid)>=x) R=mid;
                                else L=mid+1;
                        }
                        ans+=query(1,1,L);
                        pos=L%n;
                }

注意这里m--的条件并不是x还有剩余,而是pos到了0(否则就可以得到WA80的好成绩。。。)

Dele(1,t[1].pos);

最后把这个水瓶删除即可。

关于循环外:

if(m)
{
        ans+=t[1].sum*(m-1);
        for(int i=pos+1;i<=n;i++)
        {
                if(S>=w[i]+a[i]*ans) ans++;
        }
}

因为有可能下一个水瓶用完是在m轮之后,所以要把m轮转完

最后就可以AC本题啦!在OJ上跑了3000ms(three_D大神跑了400ms)

转载于:https://www.cnblogs.com/AthosD/articles/11373466.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值