P14058【MX-X21-T3】[IAMOI R5] 两个人的演唱会

P14058 【MX-X21-T3】[IAMOI R5] 两个人的演唱会

https://www.luogu.com.cn/problem/P14058

题目背景

许多年之后,她站在璀璨的舞台上,望着底下汹涌的粉丝,却失神了片刻——

在漫长的追梦路上,她总会想起那道信任的目光,和自己的第一场「演唱会」。

没有绚丽的灯光,没有华美的妆造,有的只是一个孩子为了鼓励另一个孩子追求梦想而搭建起的舞台。

题目描述

知更鸟有一个长度为 \(n\) 的,由正整数组成的环 \(a_1, \ldots, a_n\),她要你将这个环切成若干段,使得所有段的段内极差都小于等于 \(m\),求分成的最小段数。

输入格式

本题有多组测试数据。

输入的第一行包含一个整数 \(T\),表示测试数据的组数。

接下来包含 \(T\) 组数据,对于每组数据:

  • 第一行包含两个正整数 \(n,m\)

  • 第二行包含 \(n\) 个正整数 \(a_1\sim a_n\)

输出格式

对于每组数据输出一行包含一个整数,表示答案。

输入输出样例 #1

输入 #1

3
5 5
4 1 10 6 7
6 138
1 3 8 98 40 138
6 38
1 3 8 98 40 138

输出 #1

2
1
4

说明/提示

【样例解释】

对于第一组数据,把这个环切成 \(2\) 段,第一段上的数为 \(4,1\),第二段上的数为 \(10,6,7\),每段的极差都不超过 \(5\),可以证明不存在段数更少的划分方案,答案为 \(2\)

对于第二组数据,可以不切这个环,可以证明不存在段数更少的划分方案,答案为 \(1\)

对于第三组数据,把这个环切成 \(4\) 段,第一段上的数为 \(1,3,8\),第二段上的数为 \(98\),第三段上的数为 \(40\),第四段上的数为 \(138\),每段的极差都不超过 \(38\),可以证明不存在段数更少的划分方案,答案为 \(4\)

【数据范围】

本题采用捆绑测试。

\(\sum n\) 表示单个测试点中 \(n\) 的和。

\(\text{Subtask}\) \(\sum n\le\) 特殊性质 分数
\(1\) \(20\) \(11\)
\(2\) \(500\) \(5\)
\(3\) \(5000\) \(13\)
\(4\) \(3\times 10^5\) \(19\)
\(5\) \(1.5\times 10^6\) \(17\)
\(6\) \(3\times 10^7\) A \(5\)
\(7\) \(3\times 10^7\) B \(11\)
\(8\) \(3 \times 10^7\) \(19\)
  • 特殊性质 A:\(\forall i\in[1,n],a_i\le 2\)

  • 特殊性质 B:\(a_1-a_n>m\)

对于所有数据,保证 \(1\le T\le 5\times10^6\)\(1 \le n,\sum n\le 3 \times 10^7\)\(1 \le m,a_i \le 10^9\)

【提示】

数据输入输出的规模可能较大,请选手注意输入读取和输出方式的效率。请注意本题特别的时空限制。

题解

贪心的取一个最小值所包含的区间断开,接着能接就接否则就断开。

#include<bits/stdc++.h>
#define wk(x) write(x),putchar(' ')
#define wh(x) write(x),putchar('\n')
#define N 100000005
#define int long long
using namespace std;
int n,m,k,jk,ans,sum,num,cnt,tot;
int dis[N],vis[N];

int read(int &x){
	x=0;int ff=1;char ch=getchar();
	while(!(ch>='0'&&ch<='9')){ff=(ch=='-'?-1:ff);ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	x*=ff;return x;
}

void write(int x){
	if(x<0){x=-x;putchar('-');}
	if(x>=10) write(x/10);
	putchar('0'+(x%10));return;
}

signed main(){
	read(jk);while(jk--){
		read(n),read(m);ans=2e9;tot=0;
		for(int i=1;i<=n;i++){
			read(dis[i]);dis[i+n]=dis[i+2*n]=dis[i];
			ans=min(ans,dis[i]);tot=max(tot,dis[i]); 
		}int l,r;
		if(tot-ans<=m){
			wh(1);
			continue;
		}
		for(int i=n+1;i<=2*n;i++){
			if(dis[i]==ans){
				l=i;r=i;
				break;
			}
		}int x=0,y=0,z=l;cnt=0;
		while(x<n&&dis[l-1]-ans<=m) l--,x++;
		while(x+y<n&&dis[r+1]-ans<=m) r++,y++;
		for(int i=r+1;i<r+n-x-y;i++) vis[++cnt]=dis[i];
		int mx=0,mn=2e9;sum=0;
		for(int i=1;i<=cnt;i++){
			mx=max(mx,vis[i]);mn=min(mn,vis[i]);
			if(mx-mn>m){
				mx=mn=vis[i];
				sum++;//printf("|");
			}//wk(vis[i]);
//			if(mx==mn&&mn==vis[i]) 
//			printf("|");
		}wh(sum+2);
	} 
	return 0;
}
posted @ 2025-11-27 12:02  Red_river_hzh  阅读(1)  评论(0)    收藏  举报