题意:
有n个火车站,位于一条坐标轴上,坐标为xixi,现在,葱花从原点出发,到每个火车站的商店购物,并最后回到家中。已知每个商店的购物时间分别为titi
但这个火车非常的扯,它只有1班车,还只能从原点到点(L,0)以1的速度横向鬼畜。葱花只能乘火车移动,只有在火车经过它所在的车站时才能上车,只有在火车到达它想到的车站时才能下车。
求葱花购物完回家的最断时间。
n≤300000n≤300000
分析:
显然,最终的时间一定为x×2Lx×2L(x表示火车在这段时间的鬼畜次数)
并且,很显然当葱花购物完毕后,必然会在第一次车到站时上车。
然后,对每个ti≥2Lti≥2L,我们可以直接将其mod2∗Lmod2∗L
用一个二元组(x,y)来表示每个点:
若ti≤2∗(L−xi)ti≤2∗(L−xi),x=0x=0否则x=1x=1,表示:若车从左边来,那么当x=0时,它会从左边离开,当x=1时从右边离开。
同样地
若ti≤2∗xiti≤2∗xi,y=0y=0否则y=1y=1,表示,若车从右边来,那么当y=0y=0时,它会从右边离开,否则从左边离开。
若出现了ti=0ti=0的情况(即之前取模之后变为了0),根据定义应该修改为(1,1)。
很容易发现,一定不会出现(1,0)(1,0)在(0,1)(0,1)之前:因为L−xiL−xi是递减的,xixi是递增的,所以如果存在一个值x,使得2∗xi≥ti>2∗(L−xi)2∗xi≥ti>2∗(L−xi),那么不可能当xixi更大,(L−xi)(L−xi)更小时,2∗xi<ti≤2∗(L−xi)2∗xi<ti≤2∗(L−xi)
考虑如何求出答案:我们从最左边出发,若从左边经过一个点,若x=0x=0,那么可以不增加代价,反向离开;若x=1x=1,那么可以增加1的代价,正向离开。对从右边经过是同理的。每到达一次端点(原点或(L,0)),代价再次+1。显然多走0的点是最优的。并且对于(1,1)的点,无论怎么经过它,代价都要+1
所以,先删去所有(1,1)的点,再将不同的点的0配对,即(1,0)或(0,0)与在它右边的(0,1)或(0,0)配对。并删去配对的点,最后一定形成了形如:(0,1)(0,1)……(0,0)(1,0)(1,0)……的样子,中间的(0,0)最多只有一个。
再考虑剩下的答案如何求,设剩下的点有SS个。很显然,只有当最右端没有被匹配,并且为(0,1)或(0,0)时,答案为否则,均为S+1S+1
证明很简单,若最右端为(0,1)或(0,0),那么就可以不经过最右端的点,直接返回左边,而如果最右端之前被匹配过或为(1,0),那么必然会经过最右端的点,所以代价要+1
注意实现的时候要使得右端点尽可能不被匹配到,并且要注意最大匹配的写法(贪心思路O(n)做)
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
#define SF scanf
#define PF printf
#define MAXN 300010
using namespace std;
typedef long long ll;
int n;
ll L,ans,x[MAXN],t[MAXN];
pair<int,int> s[MAXN];
stack<int> q[2];
bool del[MAXN];
int main(){
//freopen("datax.in","r",stdin);
//freopen("data.out","w",stdout);
SF("%d%lld",&n,&L);
for(int i=0;i<n;i++)
SF("%lld",&x[i]);
for(int i=0;i<n;i++){
SF("%lld",&t[i]);
ans+=(t[i]/(2ll*L))*2ll*L;
t[i]%=(2ll*L);
}
//PF("[%lld]",ans);
bool flag=0;
for(int i=0;i<n;i++){
if(t[i]!=0){
flag=1;
if(t[i]<=2ll*(L-x[i]))
s[i].first=0;
else
s[i].first=1;
if(t[i]<=2ll*x[i])
s[i].second=0;
else
s[i].second=1;
}
else{
s[i].first=s[i].second=1;
}
}
for(int i=0;i<n;i++)
if(s[i].first==1&&s[i].second==1){
del[i]=1;
if(t[i]!=0)
ans+=2ll*L;
//PF("********(%lld %lld)******",t[i],x[i]);
}
for(int i=0;i<n-1;i++){
if(del[i]==1)
continue;
if(s[i].first==0&&s[i].second==1){
if(!q[1].empty()){
del[q[1].top()]=1;
del[i]=1;
q[1].pop();
ans+=2ll*L;
}
else if(!q[0].empty()){
del[q[0].top()]=1;
del[i]=1;
q[0].pop();
ans+=2ll*L;
}
}
else if(s[i].second==0){
q[s[i].first].push(i);
}
}
while(!q[1].empty())
q[1].pop();
while(!q[0].empty())
q[0].pop();
//PF("{%lld}",ans);
for(int i=0;i<n-1;i++){
if(del[i]==1||(s[i].first==0&&s[i].second==1))
continue;
if(s[i].first==0){
if(!q[1].empty()){
del[i]=1;
del[q[1].top()]=1;
q[1].pop();
ans+=2ll*L;
}
else if(!q[0].empty()){
del[i]=1;
del[q[0].top()]=1;
q[0].pop();
ans+=2ll*L;
}
else
q[0].push(i);
}
else
q[1].push(i);
}
if(s[n-1].first==0&&del[n-1]==0){
for(int i=0;i<n-1;i++)
if(del[i]==0&&s[i].second==0){
del[i]=1;
del[n-1]=1;
ans+=2ll*L;
break;
}
}
/*for(int i=0;i<n;i++)
PF("[%d %d %d]\n",s[i].first,s[i].second,del[i]);
PF("{%lld}",ans);*/
ll res=0,sum=0;
for(int i=0;i<n;i++)
if(del[i]==0)
sum++;
if(del[n-1]==0){
if(s[n-1].first==1&&s[n-1].second==0)
res=sum+1;
else
res=sum;
}
if(del[n-1]==1)
res=sum+1;
ans+=res*2ll*L;
PF("%lld",ans);
}