[补题]云音泛

P10837 『FLA - I』云音泛

题目描述

在梦中,秋种下了 n n n 朵凋零玫瑰。他记得,第 i i i 朵玫瑰是在时刻 t i t_i ti 种植的。

凋零玫瑰在被种下的那个时刻就立即开放,但每一株玫瑰只会开放 m m m 个时刻(在时刻 T T T 种植的玫瑰会且仅会在从时刻 T T T 到时刻 T + m − 1 T+m-1 T+m1 m m m 个时刻开放),在 m m m 个时刻后便化作再也无法挽留的灰尘,飘散在凛冽的寒风中。

他问你,假如他可以改变不超过一朵玫瑰的种植时间(选定一个 t i t_i ti 并将其修改为任意正整数),那么最多有多少个时刻有且仅有一株凋零玫瑰开放?

输入格式

第一行输入两个正整数 n , m n,m n,m

第二行输入 n n n 个正整数,第 i i i 个正整数为 t i t_i ti

输出格式

输出一行一个正整数表示答案。

样例 #1

样例输入 #1

5 4
11 9 1 3 12

样例输出 #1

14

样例 #2

样例输入 #2

13 7
6 42 58 41 20 60 2 61 45 28 45 28 12

样例输出 #2

38

提示

「样例解释 #1」

如图,使用金色标记有且仅有一株凋零玫瑰开放的时刻,使用黑色和红色标记每朵凋零玫瑰开放的时刻。

example1

将使用红色标记的玫瑰的种植时刻改为 17 17 17(将 t 1 t_1 t1 的值修改为 17 17 17,如下图)后有 14 14 14 个时刻有且仅有一株凋零玫瑰开放。可以证明不存在能够使有且仅有一株凋零玫瑰开放的时刻数量大于 14 14 14 的修改方案。

example2

「数据范围」

测试点编号 n ≤ n \leq n m ≤ m \leq m t i ≤ t_i \leq ti
1 ∼ 6 1 \sim 6 16 5000 5000 5000 5000 5000 5000 5000 5000 5000
7 ∼ 12 7 \sim 12 712 2 × 1 0 5 2 \times 10^5 2×105 2 × 1 0 5 2 \times 10^5 2×105 2 × 1 0 5 2 \times 10^5 2×105
13 ∼ 14 13 \sim 14 1314 2 × 1 0 5 2 \times 10^5 2×105 1 1 1 1 0 9 10^9 109
15 ∼ 20 15 \sim 20 1520 2 × 1 0 5 2 \times10^5 2×105 1 0 9 10^9 109 1 0 9 10^9 109

对于所有测试数据, 1 ≤ n ≤ 2 × 1 0 5 1 \leq n \leq 2 \times 10^5 1n2×105 1 ≤ m , t i ≤ 1 0 9 1 \leq m,t_i \leq 10^9 1m,ti109


思路:
原本准备离散化差分来解决的,但满不了分。
直接贪心即可:
首先,代码对玫瑰的种植时间进行排序。
然后,代码遍历排序后的玫瑰种植时间,计算相邻玫瑰种植时间之间的间隔,并累加这些间隔中有且仅有一株凋零玫瑰开放的时刻数量。
接着,代码计算修改每个玫瑰种植时间可以获得的增益,并记录最大的增益。
最后,代码输出初始时刻数量加上最大的增益,即为最终答案。

具体来说,代码中的变量 ans 表示初始时刻数量,即在不修改任何玫瑰种植时间的情况下,有且仅有一株凋零玫瑰开放的时刻数量。变量 l 和 r 分别表示当前玫瑰种植时间对应的开放时间段的左右边界。变量 add 表示最大的增益,即通过修改玫瑰的种植时间可以获得的最大增益。

代码中的两层循环分别计算了初始时刻数量和最大的增益。第一层循环计算了初始时刻数量,第二层循环计算了最大的增益。最后,代码输出初始时刻数量加上最大的增益,即为最终答案。

代码:

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
//int a[200005][2];
//int ex[200005]={};
int t[200005];
signed main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int N,M;
//	memset(ex,0,sizeof(ex)); // 初始化ex数组为0
	unsigned long long ans = 0;
	cin >> N >> M;
	for (int i = 1; i <= N; i++) {
		cin>>t[i];
//		int x;
//		cin >> x ;
//		t[i+1]=x;
//		m[x]++;
//		m[x+M]--;
	}
	
//	int index=0;
//	for(pair<int,int> e: m){  //进行离散化,将每段记录成数组,第一行为位置,第二行为长度
//		a[index][1]=e.second;
//		a[index++][0]=e.first;
//	}
	
	int add = -M;
	sort(t+1,t+N+1); // 逆序排列玫瑰种植时间
	t[0]=  -0x3f3f3f3f3f3f3f3f; // 设置哨兵,避免数组越界
	t[N+1]= 0x3f3f3f3f3f3f3f3f; // 设置哨兵,避免数组越界
	for(int i=1;i<=N;i++){ // 遍历每个玫瑰的种植时间
		long long l,r,a=0; // 定义变量l和r,分别表示当前玫瑰种植时间对应的开放时间段的左右边界,a表示当前玫瑰种植时间对应的增益
		l=max(t[i-1]+M,t[i]); // 计算左边界
		r=min(t[i]+M,t[i+1]); // 计算右边界
		if(r>l) { // 如果左边界小于右边界
			a-=(r-l); // 计算增益
			ans+=(r-l); // 累加增益
		}
		if(i>=2 && i<=N-1){ // 如果当前玫瑰不是第一个也不是最后一个
			if(t[i]<t[i-1]+M){ // 如果当前玫瑰与前一个玫瑰的间隔小于m
				l=max(t[i-2]+M,t[i]); // 计算左边界
				r=min(t[i-1]+M,t[i+1]); // 计算右边界
				if(r>l) a+=(r-l); // 如果左边界小于右边界,计算增益
			}
			if(t[i]+M>t[i+1]){ // 如果当前玫瑰与后一个玫瑰的间隔小于m
				r=min(t[i+2],t[i]+M); // 计算右边界
				l=max(t[i+1],t[i-1]+M); // 计算左边界
				if(r>l) a+=(r-l); // 如果左边界小于右边界,计算增益
			}
		}
		else if(i==1){ // 如果当前玫瑰是第一个
			if(t[i]+M>t[i+1]){ // 如果当前玫瑰与后一个玫瑰的间隔小于m
				r=min(t[i+2],t[i]+M); // 计算右边界
				l=max(t[i+1],t[i-1]+M); // 计算左边界
				if(r>l) a+=(r-l); // 如果左边界小于右边界,计算增益
			}
		}
		else if(i==N){ // 如果当前玫瑰是最后一个
			if(t[i]<t[i-1]+M){ // 如果当前玫瑰与前一个玫瑰的间隔小于m
				l=max(t[i-2]+M,t[i]); // 计算左边界
				r=min(t[i-1]+M,t[i+1]); // 计算右边界
				if(r>l) a+=(r-l); // 如果左边界小于右边界,计算增益
			}
		}
		add=max(add,a); // 更新最大的增益
	}

	
//	// 计算初始时刻数量
//	for(int i=1;i<index;i++){
//		a[i][1]+=a[i-1][1]; 
//		if(a[i-1][1] == 1 )
//			ans += a[i][0]-a[i-1][0];
//	}
	
	// 输出最终答案
	cout <<ans + M + add ;
	return 0;
}
  • 9
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值