洛谷P11940 [CrCPC 2024] 搬东西 题解

这个样例给的挺好的,可以引导我这个蒟蒻想到正解。

首先这个题一眼就是这样贪心:

从最左边走到最右边再回来,但由于起点终点固定,中间可以空一段(图中 \((2,4)\) 的位置,注意是开区间)

然后你就 WA 了,你看了看样例 2:

你发现可以在走的时候绕个圈,可以使这个圈后边的那一段可以空出来。

你又发现如果不把这个圈空出来,会对答案贡献两次此任务的长度,但如果空出来了,就需要走三次。所以空出来时,该圈不但不能省距离,还要倒贴该圈的长度的代价。

那么我们尝试选择空出来的这一段,看空出来哪一段可以使省的路程最大。

聪明的你一定看出来这是一个最大子段和问题。对于每个逆向行驶的任务,他们的贡献是负的这个任务的长度。每个逆向行驶的任务就是正的任务的长度。

答案就是 \(2\times(maxr-minl)-ans\),其中 \(maxr\) 是最右边的任务端点,\(minl\) 是最左边的任务端点,\(ans\) 是最大能省多少距离。

然后你这样算发现又 WA 了,原因如下:

所以要反着再跑一遍,看看哪个更优。

点击查看代码
//写法上,实在调不出来,参考了vegetableYe大佬的题解qwq 
#include<bits/stdc++.h>
#define wef(i,l,r) for(int i=l;i<=r;i++)
#define few(i,r,l) for(int i=r;i>=l;i--)
#define lowbit(x) (x&-x)
#define pii pair<int,int>
#define piii array<int,3>
#define fir first
#define sec second
using ll=long long;
const int inf=0x3f3f3f3f;
using namespace std;
#define int ll
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x*f;}
inline void write(auto x,char fg=0){bool neg=0;if(x<0){neg=1;putchar('-');}static int sta[40];int top=0;do{sta[top++]=x%10;x/=10;}while(x);if(neg) while(top) putchar('0'-sta[--top]);	else while(top) putchar('0'+sta[--top]);if(fg) putchar(fg);}
inline void putstr(string a){int t=a.size();for(int i=0;i<t;i++) putchar(a[i]);}
int s[100005],t[100005];
int solve(int n){
	vector<pii> a;
	wef(i,1,n){
		if(s[i]>t[i]){//这里运用到了类似扫描线入边出边的思想,左端点为1,右端点为-1,用于判断当前段有没有逆向任务。 
			a.emplace_back(t[i],1);
			a.emplace_back(s[i],-1);
		}
		else{
			a.emplace_back(s[i],0);
			a.emplace_back(t[i],0);
		}
	}
	sort(a.begin(),a.end());
	int in=a[0].sec;
	int s=0,res=0;
	wef(i,1,a.size()-1){
		int d=a[i].fir-a[i-1].fir;
		if(d>0){
			if(in) s=max(-d,s-d);//最大子段和 
			else s=max(d,s+d);
			res=max(res,s);
		}
		in+=a[i].sec;
	}
	return res;
}
signed main(){
	int l=read(),n=read();
	int minn=inf,maxn=0;
	wef(i,1,n){
		s[i]=read(),t[i]=read();
		minn=min({minn,s[i],t[i]});
		maxn=max({maxn,s[i],t[i]});
	}
	int res=solve(n);
	wef(i,1,n) s[i]=-s[i],t[i]=-t[i];
	res=max(res,solve(n));
	write((maxn-minn)*2-res);
	return 0;
}
posted @ 2026-04-22 20:49  vivid/stasis  阅读(31)  评论(0)    收藏  举报