AcWing 4908. 饥饿的牛

贝茜是一头饥饿的牛。

每天晚上,如果牛棚中还有干草的话,贝茜都会吃掉其中的一捆。

初始时,牛棚中没有干草。

为了让贝茜不被饿死,农夫约翰制定了 N个给贝茜送干草的计划。

其中第 i个计划是在第 di 天的白天给贝茜送去 bi 捆干草。

这些计划互不冲突,保证 1≤d1<d2<…<dN≤T

输入样例1:
1 5
1 2
输出样例1:
2
样例1解释
两捆干草在第 1 天早上被送到了牛棚,所以贝茜第 1,2 天有干草吃。

输入样例2:
2 5
1 2
5 10
输出样例2:
3
样例2解释
两捆干草在第 1 天早上被送到了牛棚,所以贝茜第 1,2 天有干草吃。

10 捆干草在第 5 天早上被送到了牛棚,所以贝茜第 5 天有干草吃。

输入样例3:
2 5
1 10
5 10
输出样例3:
5
10捆干草在第 1天早上被送到了牛棚,所以贝茜第 1∼5 天都有干草吃。

思路:

这个问题的中心思想就是,把1 ~ t 这段天数看成一个线段,每个 di 天的时候给 bi 捆草,也就是说 di ~ di+bi 这个线段是有草吃的,那想要得到的结果就是在一个大线段中有许多这样的小线段,问大线段上被小线段覆盖过的整数点有多少个。

可以看到,题目中天数的数据范围是10的14次幂,所以说按照你的第一反应,有草吃的那天bool值为1,没草吃bool值为0,然后遍历一遍是行不通的。

注意到 d 的数量,即发草的天数是有限的,N范围内,那既然所有天数看不了,我们就看所有的 d 就好了,回到上面我们讲的思路,也就是每次都看小线段的起始点。我们用一个 k 表示之前的草最多可以吃到哪一天。因为开始 k=0 ,所以用一个 f 来特判一下是不是第一次。

如果 f == 0,说明是第一次,那要看 d 是不是1,是一的话说明第一天有草吃,那当前的草最多就可以吃到 k+b 天,以此更新k。如果d不是1,那说明 d 之前都是没草吃的,这里我们用 res 来记录没有草吃的天数。然后用d+b-1来更新 k 。

如果 f 不是 0 ,说明现在不是第一次发草,那就看 d 和 k 的大小来进行比较就行了,d 大于 k+1 的话说明k ~ d 这段时间没草吃,否则就是有草吃,不断更新 k 值就行了。

需要注意的是,在更新res 的时候,要注意看天数和 t 的关系。

代码:

#include<bits/stdc++.h>
using namespace std;

int main(){
    long long int n , t;
    cin >> n >> t;
    long long int d;
    int b;
    long long int k = 0;
    int f = 0;
    int z = 0;
    long long int res = 0;
    for(int i = 0 ; i < n ; i++){
        cin >> d >> b;
        if(z == 1)
            break;
        if(f == 0){
            f = 1;
            if(d == 1){
                k = k + b;
                if(k >= t)
                    z = 1;
            }
            else{
                if(d < t)
                    res = res + d - 1;
                else
                    res = res + t , z = 1;
                k = d + b - 1;
            }
        }
        else{
            if(d > k+1){
                if(d <= t)
                    res += d-k-1;
                else
                    res += t-k , z = 1;
                k = d + b - 1;
            }
            else{
                k = k + b;
            }
        }
    }
    // cout << res << "*** " << endl;
    if(z!=1 && k < t)
        res += t - k;
    cout << t - res << endl;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值