算法作业 | BJTU1882 sqy 的锡纸烫(递推)

题目:https://citel.bjtu.edu.cn/acm/problem/1882

前不久 sqy 老师花了大价钱,去做了一个帅气的锡纸烫。有着商业眼光的 sqy 一下子发现了大商机,于是他自己开了一家美容美发店。

sqy 找了刚刚做完纹理烫的大预言家 cbj 预测了未来,发现每个顾客都只在白天来美发店,并且第一次来店里的时候都会充一次价值 x i x_i xi 的卡,然后从第二天开始,每天白天都会来这里打理头发,而 sqy 仅收取成本价 1 元钱来吸引顾客,直到把卡掏空为止,这个顾客就再也不会回来。

黑心商人 sqy 找大预言家要来了每个顾客的充卡时间和充值金额,他准备在某一天晚上跑路,他想知道自己最多能卷走多少钱。

输入数据
第一行包括一个整数 n(1≤n≤ 1 0 5 10^5 105) 表示有 n 个顾客。
接下来共 n 行,每i+1行包括两个整数 x i x_i xi, y i y_i yi 表示第 x i x_i xi 天一个顾客来充值了 yi 元 (1≤ x i x_i xi 1 0 6 10^6 106,0≤ y i y_i yi 2 31 − 1 2^{31}−1 2311)。

输出数据
输出一行包括一个整数 ans,表示 sqy 最多能卷走多少钱。

样例输入

5
1 5
2 5
3 5
4 5
5 5

样例输出
15
//在第五天的时候,第一个人消费4元还剩1元,第二个人消费3元还剩2元,第三个人消费2元还剩3元,第四个人消费1元还剩4元,第五个人还没有开始消费就被卷钱跑路了。

分析
核心是构建递推公式:
a i + 1 = a i + m i + 1 − ( n i − b i ) a_{i+1} = a_{i} + m_{i+1} - (n_i-b_i) ai+1=ai+mi+1(nibi)
其中:
a i + 1 a_{i+1} ai+1是第i+1天跑路时的累计收益; m i + 1 m_{i+1} mi+1是当天的收益; ( n i − b i ) (n_i-b_i) (nibi)是当天的支出,也就是美发店中剩下的人数(累计来的人数-累计走的人数,通过遍历数组计算得到)。

代码

//
// Created by ZixinQin on 2021/9/17.
//
# include <iostream>
# include <cstdio>
# include <algorithm>
using namespace std;

struct Record{
    int come;
    int charge;
    int leave;
}re[1000100];

int benefit[1000100];
int come[1000100];
int leave[1000100];
int charge[1000100];

int main() {
    int N;
    //cin>>N;
    scanf("%d", &N);
    int max_day = 0;
    int max_charge = 0;
    for (int i = 1; i <= N; ++i) {
        int day, charge;
        //cin>>day>>charge;
        scanf("%d %d", &day, &charge);
        re[day].charge += charge;
        re[day].come += 1;
        if(day+charge<1000100)
            re[day+charge].leave += 1;
        if (day > max_day)
            max_day = day;
        if (charge > max_charge)
            max_charge = charge;
    }
    come[0] = 0;
    leave[0] = 0;
    for(int i=1;i<=max_day;i++){
        charge[i] = re[i].charge; //  charge in
        come[i] = come[i-1] + re[i].come;// total come
        leave[i] = leave[i-1] + re[i].leave; // total leave
        //cout<<i<<" "<<charge[i]<<" "<<come[i]<<" "<<leave[i]<<endl;
    }

    benefit[1] = charge[1];
    come[0] = 0;
    leave[0]= 0;
    int max_benefit = 0;
    for(int i=2;i<=max_day;i++){
        benefit[i] = benefit[i-1] + charge[i] - (come[i-1]-leave[i-1]);
        //cout<<benefit[i]<<endl;
        if(benefit[i]>max_benefit)
            max_benefit = benefit[i];
    }
    cout<<max_benefit<<endl;

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值