http://codeforces.com/contest/1201/problem/D
题意:
有一个n*m的方格,方格上有k个宝藏,一个人从(1,1)出发,可以向左或者向右走,但不能向下走。给出q个列,在这些列上可以向上走,其他列不能向上走。可以重复经过同一个点。求从(1,1)出发,经过所有宝藏的最短路径长度
思路:这道题目,思路比较好想,就是贪心的选择每层最左边最右边宝藏的相邻的四个楼梯,然后和前面求得情况求走的距离的累加,枚举每一个出口,每次选择距离最小的就是该出口的最小值。
但是这道题细节很多
左右最近楼梯通过二分求得后,枚举每一个出口,和之前情况取最小值
分别讨论最左宝藏和最右宝藏在出口左端右端情况
最后一层只需要讨论到左右宝藏的情况
最后加上最低高度
#include<bits/stdc++.h>
#include<tr1/unordered_map>
#define fi first
#define se second
#define show(a) cout<<a<<endl;
#define show2(a,b) cout<<a<<" "<<b<<endl;
#define show3(a,b,c) cout<<a<<" "<<b<<" "<<c<<endl;
using namespace std;
typedef long long ll;
typedef pair<ll, ll> P;
typedef pair<P, ll> LP;
const ll inf = 1e17 + 10;
const int N = 3e6 + 10;
const ll mod = 10007;
const int base=131;
tr1::unordered_map<ll,ll> mp;
ll n,m,id,t,x,y,k,q;
ll num[N],vis[N],cnt;
ll l[N],r[N],a[N];
ll ans,flag;
//ll tree[N],tag[N];
set<ll> st;
vector<ll> v;
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m>>k>>q;
ll top=1;
l[1]=r[1]=1;
for(int i=1;i<=k;i++)
{
cin>>x>>y;
top=max(top,x);
if(!l[x]) l[x]=y;
else l[x]=min(l[x],y);
r[x]=max(r[x],y);
}
for(int i=1;i<=q;i++) cin>>x,st.insert(x);
vector<P> pre;
pre.push_back(P(0,1));
for(int i=1;i<top;i++)
{
if(l[i]==0&&r[i]==0) continue;
cnt=0;
auto pos1=st.lower_bound(l[i]);
if(pos1!=st.end()) a[++cnt]=*pos1;
if(pos1!=st.begin()) a[++cnt]=*(--pos1);
auto pos2=st.lower_bound(r[i]);
if(pos2!=st.end()) a[++cnt]=(*pos2);
if(pos2!=st.begin()) a[++cnt]=*(--pos2);
sort(a+1,a+cnt+1);
cnt=unique(a+1,a+cnt+1)-(a+1);
// cout<<"louti: ";for(int i=1;i<=cnt;i++) cout<<a[i]<<" ";cout<<endl;
vector<P> tmp;
for(int j=1;j<=cnt;j++)
{
ll res=inf,out=a[j];//枚举每一个出口
//show3("out",j,a[j])
for(auto p:pre)
{
ll sum=p.fi,prex=p.se;
if(prex<=out)
{
if(l[i]<=prex) sum+=2*abs(l[i]-prex);
if(r[i]>=out) sum+=2*abs(r[i]-out);
//if(out==1&&prex==1) cout<<"asfd"<<endl,show3(r[i],out,i)
}
else
{
if(r[i]>=prex) sum+=2*abs(r[i]-prex);
if(l[i]<=out) sum+=2*abs(l[i]-out);
}
sum+=abs(out-prex);
res=min(sum,res);
}
//show3(i,res,out)
tmp.push_back(P(res,out));
}
pre=tmp;
//for(auto c:pre) cout<<c.fi<<" "<<c.se<<" ";cout<<endl;
}
ans=inf;
int i=top;
for(auto p:pre)
{
ll sum=p.fi,prex=p.se;
if(prex<=l[i])
{
sum+=abs(r[i]-prex);
}
else
{
if(prex>=r[i]) sum+=abs(l[i]-prex);
else
{
sum+=min(r[i]-prex,prex-l[i])+r[i]-l[i];
}
}
ans=min(sum,ans);
}
cout<<ans+top-1<<endl;
}