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;
}