洛谷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;
}

浙公网安备 33010602011771号