题目链接:https://www.zhixincode.com/contest/1/problem/A?problem_id=2
题目大意 初始在A区的S点,在AB两个区域上有一些需要到达的点,在AB区域上只能在给定的特殊点转向或者到另一个区域,其余的点只能按照之间的方向继续行走。穿越区域需要花费代价k,从a点到b点花费代价abs(a-b),初始点S可以选择一个方向行走。
题解思路:首先我们需要构建两个区间,a区间和b区间,区间的端点都为可以转向的点,区间包含了所有需要到达的点,假如存在b区间,那么b区间一定包含于a区间,因为我们初始的s在A区域上,先从A区域走,走到a区间的一个边界然后翻到B区域,这样肯定要满足b区间比a区间要小 才在贪心策略上最优。
所以在构建完ab区间后要满足b比a小
需要注意的是,在构建a区间的时候,初始的s点也是可以转向的,虽然这个点不一定可以翻越,在图中第三种情况里也是可以作为区间端点的,在构造a区间的时候需要把s也加入到vec中排序,然后二分找一下。
主要分类就是图中的几种情况,合并起来就是区间+到区间的距离+2k(如果穿越的话)
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
const int maxn=1e6+5;
using namespace std;
pair<int,int>a[maxn];
vector<int>vec;
int main()
{
int n,r,m,k,s,p;
cin>>n>>r>>m>>k>>s;//区间长度为n r个需要到的个点 m个特俗点 穿越代价为k 起始点为s
vec.push_back(1);vec.push_back(n);
int tem;
for(int i=1;i<=r;i++)//要到的点
{
cin>>a[i].first>>a[i].second;
}
for(int i=1;i<=m;i++)//特殊点
{
cin>>tem;
vec.push_back(tem);
}
sort(vec.begin(),vec.end());
int al=n,ar=1,bl=n,br=1;
int flag=0;
for(int i=1;i<=r;i++)
{
if(a[i].second)
{
flag=1;
bl=min(bl,*(upper_bound(vec.begin(),vec.end(),a[i].first)-1));//第一个小于等于
br=max(br,*(lower_bound(vec.begin(),vec.end(),a[i].first)));//第一个大于等于
}
}
vec.push_back(s);//s点可以作为a的转向点
sort(vec.begin(),vec.end());
for(int i=1;i<=r;i++)
{
if(!a[i].second)
{
al=min(al,*(upper_bound(vec.begin(),vec.end(),a[i].first)-1));//第一个小于等于
ar=max(ar,*(lower_bound(vec.begin(),vec.end(),a[i].first)));//第一个大于等于
}
}
al=min(al,bl);ar=max(ar,br);//保证a区间要包含b区间
//cout<<al<<' '<<ar<<' '<<bl<<' '<<br<<endl;
if(!flag)
{
cout<<2*(ar-al+max(0,al-s)+max(0,s-ar))<<endl;
}
else
{
cout<<2*(k+ar-al+max(0,al-s)+max(0,s-ar))<<endl;
}
return 0;
}