CF 1000B

CF 1000B

link
题意:
自习室内有一个智能灯。

在 0 时刻,管理员会将打开电闸,并将灯点亮。

在 M 时刻,管理员会直接拉下电闸,此时,如果灯处于点亮状态,则会因为断电而熄灭。

在 0∼M 之间有 n 个不同时刻,不妨用 a1,a2,…,an 表示,其中 0<a1<a2<…<an<M。

在这 n 个时刻中的每个时刻,管理员都会拨动一次智能灯的开关,使灯的状态切换(亮变灭、灭变亮)。

现在,你可以最多额外指定一个时刻(也可以不指定),让管理员在此时刻也拨动开关一次。注意选定的时刻不能与 a1,a2,…,an 相等。

你的目的是让亮灯的总时长尽可能长。

输出这个最大亮灯总时长。
题解:
n + 1 个点,n个时间段,本身是奇数区间亮灯偶数区间灭灯,但是当选取任意一个区间操作后,都会使得这个操作后面变成偶数区间亮,奇数区间灭,因此,可以枚举每一个区间操作后的亮灯总长,取一个最大值即可。
在这里插入图片描述

Code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <set>
#include <queue>
#include <vector>
#include <map>
#include <unordered_map>
#include <cmath> 
#include <stack>
#include <iomanip> 
#define x first
#define y second
#define eps 1e-7
using namespace std;
typedef long double ld;
typedef long long LL;
typedef pair<int, int> PII;
typedef unsigned long long ULL;
const int N = 2e5 + 10, M = 30010, INF = 0x3f3f3f3f, P = 131, mod = 1e9 + 7;
int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};
int n, m;
int a[N], f[N];
int s1[N], s2[N]; 
int main () {
	cin.tie(nullptr)->sync_with_stdio(false);
		cin >> n >> m;
		for (int i = 1; i <= n; i ++ )	cin >> a[i];
		a[++ n] = m;
		s1[n] = s2[n] = 0;
		for (int i = n - 1; i >= 0; i -- ) { // 因为区间从(a1 - a0)开始,所以逆序前缀和也可以 
			s1[i] = s1[i + 1], s2[i] = s2[i + 1];
			if (i % 2 == 0) s1[i] += a[i + 1] - a[i]; // 奇区间前缀和 枚举的是区间长度 因此前缀和的是区间长度 
			else 			s2[i] += a[i + 1] - a[i]; // 偶区间前缀和			
		}
		int res = s1[0]; // 一个不选的情况,也就是所有偶数区间的和  
		for (int i = 0; i < n; i ++ ) {
			int t = a[i + 1] - a[i]; // 无论选奇数还是偶数操作,最终选的这个区间贪心下来长度贡献都是 t - 1 
			if (t == 1) continue;
			res = max(res, s1[0] - s1[i] + t - 1 + s2[i + 1]); // 分为,操作区间前面的奇数区间,操作区间,操作区间后面的偶数区间 
		}
		cout << res << endl; 	
	 return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值