题意:
有n个火车站,位于一条坐标轴上,坐标为
,现在,葱花从原点出发,到每个火车站的商店购物,并最后回到家中。已知每个商店的购物时间分别为
但这个火车非常的扯,它只有1班车,还只能从原点到点(L,0)以1的速度横向鬼畜。葱花只能乘火车移动,只有在火车经过它所在的车站时才能上车,只有在火车到达它想到的车站时才能下车。
求葱花购物完回家的最断时间。
分析:
显然,最终的时间一定为
(x表示火车在这段时间的鬼畜次数)
并且,很显然当葱花购物完毕后,必然会在第一次车到站时上车。
然后,对每个
,我们可以直接将其
用一个二元组(x,y)来表示每个点:
若
,
否则
,表示:若车从左边来,那么当x=0时,它会从左边离开,当x=1时从右边离开。
同样地
若
,
否则
,表示,若车从右边来,那么当
时,它会从右边离开,否则从左边离开。
若出现了
的情况(即之前取模之后变为了0),根据定义应该修改为(1,1)。
很容易发现,一定不会出现
在
之前:因为
是递减的,
是递增的,所以如果存在一个值x,使得
,那么不可能当
更大,
更小时,
考虑如何求出答案:我们从最左边出发,若从左边经过一个点,若 ,那么可以不增加代价,反向离开;若 ,那么可以增加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)最多只有一个。
再考虑剩下的答案如何求,设剩下的点有
个。很显然,只有当最右端没有被匹配,并且为(0,1)或(0,0)时,答案为
否则,均为
证明很简单,若最右端为(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);
}