题目大意
有n+1个车站,n条轨道,第i条轨道联通i-1和i车站,通过它要花a[i]时间,这条轨道有b[i]=1或2条车道,也就是说,他是单向还是双向的。现在有两种火车,一种从0到n,一种从n到0,有无限辆,同种的发车间隔是K。
现在请你分别确定两种火车在每个站停留的时间,确保单车道不会有两辆车相向而行,且同一条轨道(不是车道),不能同时存在两部同向的火车。
要求最小化两种火车从起点到终点的时间和。
n<=1e5,K,a[]<=1e9
解题思路
我们假设第一种每个站停留的时间(包括第0个,因为可以和另一种错开)为p[],第二种为q[]。发车间隔为K,说明我们可以在模K意义下进行。
双向轨道不用考虑,我们考虑方案对于单向轨道的合法性。(以下把双轨道忽略)
第一种火车在轨道m上开的时间为
(∑i=0..m−1a[i]+∑i=0..m−1p[i],∑i=0..ma[i]+∑i=0..m−1p[i])
(
∑
i
=
0..
m
−
1
a
[
i
]
+
∑
i
=
0..
m
−
1
p
[
i
]
,
∑
i
=
0..
m
a
[
i
]
+
∑
i
=
0..
m
−
1
p
[
i
]
)
同样,第二种
(∑i=0..m−a[i]+∑i=0..m−1−p[i],∑i=0..m−1−a[i]+∑i=0..m−1−p[i])
(
∑
i
=
0..
m
−
a
[
i
]
+
∑
i
=
0..
m
−
1
−
p
[
i
]
,
∑
i
=
0..
m
−
1
−
a
[
i
]
+
∑
i
=
0..
m
−
1
−
p
[
i
]
)
,用负号定义的好处是等下化式子方便。
合法就要保证这些区间都不相交。区间不相交可以化为区间端点不在另一个区间内。
设a[i]的前缀和为s[i]。
化出来会是这样的东西:对于每个m,
∑i=0..m(p[i]+q[i])∉(−2∗s[m],−2∗(s[m]−a[m]))
∑
i
=
0..
m
(
p
[
i
]
+
q
[
i
]
)
∉
(
−
2
∗
s
[
m
]
,
−
2
∗
(
s
[
m
]
−
a
[
m
]
)
)
注意这里如果区间覆盖了整个区间(也就是0~k-1),那么无解。
设sum[i]表示p[i]+q[i]前缀和,在模K意义下补集转化就变成每个
m,sum[m]∈(L[m],R[m])
m
,
s
u
m
[
m
]
∈
(
L
[
m
]
,
R
[
m
]
)
(有可能是L>R的区间)。
我们现在要最小化sum[n]-sum[0]。ans=sum[n]-sum[0]+s[n]*2。
发现这个相当于,你在一个数轴上,有n个区间[L[i],R[i]],你可以自己确定初始位置,然后你要走n步,走第i步的时候要确保走到第i个区间内(模意义下的“之内”),然后最小化走的距离(这个不模)。
发现关键点只有区间的端点。就非常好做了。
先不管我们初始位置,先算一些东西。
倒过来枚举。设f[i]表示站在i区间左端点上,做完i~n这些区间走的最小距离。
转移很贪心:就是你找到第一个大于i且L[i]不在[L[j],R[j]]内的j,加上L[i]走到L[j]的代价,转移即可。
很显然走到R不优。
算完之后,我们枚举我们的起点在2*n个点中的哪一个,找到最大的j使得前j个区间都包含起点,用f[j]转移即可。
时间复杂度O(n log n)
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<set>
#include<map>
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a=(a>b)?a:b)
#define cmin(a,b) (a=(a<b)?a:b)
typedef long long ll;
const int N=1e5+5,M=4e5+5,mo=1e9+7;
ll tr[M],a[N],b[N],s[N],n,K,i,j,k,L[N],R[N],v[M],m,f[N],ans;
void change(ll x,ll l,ll r,ll i,ll j,ll v)
{
if (i>j) return ;
if (l==i&&j==r)
{
tr[x]=v;
return ;
}
if (tr[x]) tr[x*2]=tr[x*2+1]=tr[x],tr[x]=0;
ll m=(l+r)/2;
if (m>=j) change(x*2,l,m,i,j,v);
else if (m<i) change(x*2+1,m+1,r,i,j,v);
else change(x*2,l,m,i,m,v),change(x*2+1,m+1,r,m+1,j,v);
}
ll get(ll x,ll l,ll r,ll p)
{
if (l==r) return tr[x];
if (tr[x]) tr[x*2]=tr[x*2+1]=tr[x],tr[x]=0;
ll m=(l+r)/2;
if (m>=p) return get(x*2,l,m,p);else return get(x*2+1,m+1,r,p);
}
ll calc(ll x)
{
ll y=get(1,1,m,x);
if (!y) return 0;
return f[y]+(v[L[y]]-v[x]+K)%K;
}
int main()
{
freopen("t9.in","r",stdin);
freopen("t9.out","w",stdout);
scanf("%lld %lld\n",&n,&K);
fo(i,1,n)
{
scanf("%lld %lld",a+i,b+i);
s[i]=s[i-1]+a[i];
if (b[i]==1&&2*a[i]>K)
{
printf("-1\n");
return 0;
}
}
fo(i,1,n)
if (b[i]==1)
{
L[i]=((-2*s[i])%K+K)%K;
R[i]=((-2*s[i-1])%K+K)%K;
swap(L[i],R[i]);
}else L[i]=0,R[i]=K-1;
fo(i,1,n) v[++m]=L[i],v[++m]=R[i];
sort(v+1,v+m+1);
m=unique(v+1,v+m+1)-v-1;
fd(i,n,1)
{
L[i]=lower_bound(v+1,v+m+1,L[i])-v;
R[i]=lower_bound(v+1,v+m+1,R[i])-v;
f[i]=calc(L[i]);
if (L[i]>R[i])
change(1,1,m,R[i]+1,L[i]-1,i);
else change(1,1,m,1,L[i]-1,i),change(1,1,m,R[i]+1,m,i);
}
ans=f[1];
fo(i,1,m)
ans=min(ans,calc(i));
printf("%lld\n",s[n]*2+ans);
}