[题解]CF1666E Even Split

CF1666E Even Split

二分答案好题。

下文中,记 Segmentland 的长度为 \(s\)

我们先不考虑输出方案,仅考虑如何计算最小极差 \(d\)

不难 \(d\) 具有单调性,可以二分求解。

对于每一个 \(d\),我们可以枚举区间长度的下界 \(l\),再判定能否做到所有区间的长度都在 \([l,l+d]\) 内。

我们发现这个 \(l\) 也是可以二分的,原因是我们可以 \(O(n)\) 判定当前 \(l\) 的值是偏大、偏小还是正好,可参照下面的代码:

int check(int l,int r){//长度在[l,r]内是否合法(-1为小了,0为正好,1为大了)
	int x=0,y=0;//x,y存储可能的右端点范围
	for(int i=1;i<=n;i++){
		if(x+l>a[i+1]) return 1;
		if(y+r<a[i]) return -1;
		x=max(x+l,a[i]);
		y=min(y+r,a[i+1]);
	}
	if(x>s) return 1;
	if(y<s) return -1;
	return 0;
}

这样我们就能在 \(O(n\log n\log s)\) 的复杂度内完成求解。

接下来考虑如何输出方案。

令第 \(i\) 个分界点的位置为 \(d_i\)(有 \(d_0=0,d_n=s\)),长度区间为 \([mn,mx]\)

则我们的构造需要满足的条件为:

  • \(d_i\in[a_i,a_{i+1}]\)
  • \(d_i-d_{i-1}\in [mn,mx]\)

前面的过程保证了一定存在合法的方案,所以我们尽可能紧贴着下界构造。即:

  • 先对于 \(i=1,2,\dots,n\),令 \(d_i=\max(a_i,d_{i-1}+mn)\)
  • 再对于 \(i=n,\dots,2,1\),令 \(d_{i-1}=\max(d_{i-1},d_i-mx)\)
点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int s,n,a[N],mn,mx,d[N];
int check2(int l,int r){//长度在[l,r]内是否合法(-1为小了)
	int x=0,y=0;
	mn=l,mx=r;
	for(int i=1;i<=n;i++){
		if(x+l>a[i+1]) return 1;
		if(y+r<a[i]) return -1;
		x=max(x+l,a[i]);
		y=min(y+r,a[i+1]);
	}
	if(x>s) return 1;
	if(y<s) return -1;
	return 0;
}
bool check(int x){//x作为极差是否合法
	int l=0,r=s;
	while(l<=r){
		int mid=(l+r)>>1,t=check2(mid,mid+x);
		if(t==-1) l=mid+1;
		else if(t==1) r=mid-1;
		else return 1;
	}
	return 0;
}
void get_ans(int x){
	check(x);
	d[n]=s;
	for(int i=1;i<n;i++) d[i]=max(d[i-1]+mn,a[i]);
	for(int i=n;i;i--) d[i-1]=min(d[i-1],d[i]-mx);
	for(int i=1;i<=n;i++) cout<<d[i-1]<<" "<<d[i]<<"\n";
}
signed main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	cin>>s>>n;
	for(int i=1;i<=n;i++) cin>>a[i];
	a[n+1]=s;
	int l=0,r=s;
	while(l<r){
		int mid=(l+r)>>1;
		if(check(mid)){
			r=mid;
		}else{
			l=mid+1;
		}
	}
	get_ans(l);
	return 0;
}
posted @ 2025-11-05 16:15  Sinktank  阅读(6)  评论(0)    收藏  举报
★CLICK FOR MORE INFO★ TOP-BOTTOM-THEME
Enable/Disable Transition
Copyright © 2023 ~ 2025 Sinktank - 1328312655@qq.com
Illustration from 稲葉曇『リレイアウター/Relayouter/中继输出者』,by ぬくぬくにぎりめし.