Light It Up Codeforces 1000B(思维+贪心)

本文详细解析 Codeforces 1000B 题目,通过前缀和记录灯的开关状态,采用贪心策略确定最佳时间点以最大化亮灯时长。介绍了两种情况下的具体实现思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Light It Up Codeforces 1000B

题意:

给你一个长度为n的时刻数组,和最大时刻m。有一个灯,这个时钟从0时开始亮,然后没经过一个数组上的点,亮灭会翻转一次。在你可以在任意时刻加入一个时间,求这个灯亮最大时间

分析:

可以先使用前缀和记录下灯开的总时长和灯关的总时长,然后贪心,对每个点进行分析,为了让亮的时间最长每次将灯灭的区间分割,并且分割点和原有点的间隔为1

情况1:
枚举的位置是第奇数个位置(从1开始)那么这个点i前一个区间是开的,后一个区间是关的,为了让开灯时间更长我们将新的点插入到a[i]+1位置即可,这样后面的关灯的区间全部被翻转成开灯,而i位置后面关灯时间长度变成了了,可以通过前缀和求出新的总时长,然后比较最大值
这里写图片描述

这里写图片描述

情况2:
如果枚举到了第偶数个位置i,那么i前面是关的,后面是开的
这里写图片描述
这样我们仍然是前面关区间中插入点,插入到a[i]-1的位置即可,这样i后面的关区间全部翻转成开的,并且前面多了长度为1的开的区间,求和比较最大值
这里写图片描述

code:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int maxn = 100005;
int n,m;
int a[maxn];
int on[maxn],off[maxn];
int main(){
    scanf("%d%d",&n,&m);
    a[0] = 0;
    for(int i = 1; i <= n; i++){
        scanf("%d",&a[i]);
    }
    a[n+1] = m;
    int flag = 1;
    for(int i = 1; i <= n+1; i++){
        if(flag){//记录开灯时间长度前缀和
            on[i] = on[i-1] + a[i] - a[i-1];
            off[i] = off[i-1];//关灯长度不变
        }
        else{//下面同理
            off[i] = off[i-1] + a[i] - a[i-1];
            on[i] = on[i-1];
        }
        flag = !flag;
    }
    int maxt = on[n+1];
    int tmp;
    for(int i = 1; i <= n; i++){
        tmp = 0;
        if(a[i] - a[i-1] > 1 || a[i+1] - a[i] > 1){//因为插入点之和i位置差1,所以至少和前一个位置长度大于1
            if(i % 2){奇数位置往后+1的位置插
                tmp = on[i] + off[n+1] - off[i] - 1;//关灯时间-1后全部变成开灯
            }
            else{//偶数位置插,前面关灯区间减1多了长度为1的开灯时间,之后的关灯区间全变成开灯
                tmp = on[i] + off[n+1] - off[i] + 1;
            }
        }
        maxt = max(maxt,tmp);
    }
    printf("%d\n",maxt);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值