AcWing 3774. 亮灯时长
原题链接
题解
题目描述
自习室内有一个智能灯。
在 0 时刻,管理员会将打开电闸,并将灯点亮。
在 M 时刻,管理员会直接拉下电闸,此时,如果灯处于点亮状态,则会因为断电而熄灭。
在 0∼M 之间有 n 个不同时刻,不妨用 a1,a2,…,an 表示,其中 0<a1<a2<…<an<M。
在这** n 个时刻中的每个时刻,管理员都会拨动一次智能灯的开关,使灯的状态切换**(亮变灭、灭变亮)。
现在,你可以最多额外指定一个时刻(也可以不指定),让管理员在此时刻也拨动开关一次。注意选定的时刻不能与 a1,a2,…,an相等。
你的目的是让亮灯的总时长尽可能长。
输出这个最大亮灯总时长。
输入格式
第一行包含整数 T,表示共有 T组测试数据。
每组数据,第一行包含两个整数 n和 M。第二行包含 n个整数 a1,a2,…,an。
输出格式
输出一个整数,表示最大亮灯总时长。
数据范围
1≤T≤30,
1≤n≤10^5,
2≤M≤10^9,
0<a1<a2<…<an<M。
同一测试点内所有 n 的和不超过 10^5。
分析
后/前缀和 贪心 O(n)
题目要求:可以选择加入一个不同时刻,使灯的状态多切换一次,让亮灯的时间最长。
注意到加入一个时刻后,此时刻后面区间的亮/灭状态全都变反。
用a0, a1, ... , an, an+1表示各时刻,其中a0=0, an+1=M
注意到对于[ai, aj]区间:
i为偶数,j为奇数时,灯亮
i为奇数,j为偶数时,灯灭
可以用一个后缀和s[i]表示从ai时刻开始到M时刻的亮/灭总时长,若i为偶数,表示亮灯总时长,奇数表示灭灯总时长。
则s[0]表示原始的亮灯总时长。
显然,如果加入一个时刻,要么在一个亮灯的区间加入,要么在一个灭灯的区间加入。
一旦选择一个区间[ai, aj]加入一个时刻x,这个区间后面(取反)和前面(不变)亮灯的时长是确定的,只需要考虑x如何插入的问题:
[ai, aj]是亮灯的区间,则[ai, x]灯亮,[x, aj]灯灭,显然要aj-x最小,为1,x-ai最大,为aj-ai-1
[ai, aj]是灭灯的区间,则[ai, x]灯灭,[x, aj]灯亮,显然要x-ai最小,为1,aj-x最大,为aj-ai-1
初始化为s[0],枚举每一个区间插入,计算最大值即可。时间复杂度O(n)
C++ 代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int N = 1e5+5;
int t, n, m, a[N];
ll s[N], on;
void init() {
a[n+1] = m;
s[n+2]=s[n+1]=0;
}
int main() {
scanf("%d", &t);
a[0] = 0;
while(t --) {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d", &a[i]);
init();
for(int i = n; i >= 0; i --)
s[i] = s[i+2] + a[i+1]-a[i];
on = s[0];
for(int i = 0; i <= n; i ++) {
if(i&1) on = max(on, a[i+1]-a[i]-1 + s[0]-s[i+1] + s[i+2]);
else on = max(on, -1 + s[0]-s[i+2] + s[i+1]);
}
printf("%lld\n", on);
}
return 0;
}
原文地址:https://www.cnblogs.com/Discrete/p/15037083.html
- Android新手之旅(9) 自定义的折线图
- Android新手之旅(11) 在现有页面中插入新的view
- Docker容器学习梳理--容器间网络通信设置(Pipework和Open vSwitch)
- 温故而知新:Asp.Net中如何正确使用Session
- Android新手之旅(13) listview中数据重复的问题
- 温故而知新:HttpApplication,HttpModule,HttpContext及Asp.Net页生命周期
- proxy_pass反向代理配置中url后面加不加/的说明
- Android新手之旅(10) 嵌套布局
- C#代码也VB
- Docker容器学习梳理--SSH方式登陆容器
- Docker网络解决方案-Flannel部署记录
- Nginx的location配置规则梳理
- 统计代码行数的方法梳理
- 如何在不影响asp.net默认安全性的前提下使用ckeditor/fckeditor?
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Android ListView列表实现倒计时
- [-Flutter 自组篇-] 蛛网图+绘制+动画实践
- Kotlin类型系统竟如此简单
- 以人为本 | Android 11 的消息通知
- RxJava取消订阅的各种方式的实现
- [- Flutter 基础篇 -] ListView的使用
- Emoji表情在Android JNI中的兼容性问题详解
- 一个吸顶Item的简单实现方法分享
- [- Flutter福利篇 -] Hero转场组件共享 — 附赠-路由动画工具类
- Hue执行多条语句问题
- Android仿抖音列表效果
- com.android.support版本冲突解决方法
- [-Flutter趣玩篇-] 出神入化的Align+动画
- Hive Impala和Hue集成LDAP
- Android仿QQ分组实现二级菜单展示