题目
题意: N个人过马路,分别纵向过和横向过,红灯时只可以纵向过,绿灯时反之,纵向过需要
T
1
s
T_1s
T1s,横向过需要
T
2
s
T_2s
T2s,每个人在
t
i
t_i
ti到达马路边,求最小的等待时间和,等待时间为他开始过马路的时间减去到马路边的时间。
N
<
=
3
e
3
N<=3e3
N<=3e3
题解:
官方题解:
首先可以发现一定存在一个最优方案,所有绿灯区间长度都大于等于
T
1
T_1
T1 ,所有红灯区间长度都大于等
于
T
2
T_2
T2 。如果如果小于的话,反正这一段时间也没有办法让人过红绿灯,不如就不变了。接着考虑如果
灯在第
t
t
t时刻变成了绿灯,最优解中它会在什么时候变成红灯。(对于红灯变成绿灯的分析类似)
第一种可能性是在
t
+
T
1
t+T_1
t+T1时刻变成红灯,在这种情况下,一定有在 之前(包括 ) 时刻到达且还没有
过马路的人,不然这一段没有人能过马路。
第二种可能性是在
t
+
T
1
t+T_1
t+T1时刻之后,考虑在这段绿灯中最后过马路的那个人 ,他会在 时刻后
通过马路。因此这段绿灯在第
t
+
T
1
t+T_1
t+T1时刻结束一定不亏。
我们把所有
t
+
T
1
t+T_1
t+T1或者
t
+
T
2
t+T_2
t+T2 (取决于
i
i
i的种类) 作为关键点,设
f
i
f_i
fi为在第
i
i
i个人对应的关键切换成
另一种灯时的已经能确定过马路时间的人的总等待时间(不妨假设第
i
i
i个人是第一类人)。注意这儿已
经能确定过马路时间的人包括在
t
i
t_i
ti时刻之前到达的第一类人和第
t
i
+
T
1
t_i+T_1
ti+T1时刻之前达到的第二类人 (最
开始发现的性质保证了他们都能在
t
i
+
T
1
t_i+T_1
ti+T1) 时刻过马路。
考虑转移,首先从
t
i
+
T
1
t_i+T_1
ti+T1开始,最优方案可能会进行若干段第一种可能性的转移,接着通过一个第二
种可能性的转移直接跳到后面的某一个关键点。因为第一种可能性要求必须要有对应的人在等待,因此
第一种转移最多进行 次。我们可以枚举第一段转移进行的次数,并求出对应的总等待时间(总等
待时间的定义和 一样)。
最后要处理的就是从枚举的这 段到后面的某一个关键点之间的转移,这个把式子列出来之后可以
发现用斜率优化就能直接优化到 了。
总时间复杂度为 。
出题人说:数据造的我想吐。
蒟蒻我说:代码打的我想吐。
AC Code:
#include<bits/stdc++.h>
#define maxn 3005
#define LL long long
using namespace std;
int n,tc[2];
LL sump[maxn][2],sumt[maxn][2];
struct node{
int L,R,t,r,tp;
}a[maxn],b[maxn];
struct type_one_node{
int L,R,r,tp;
LL dp;
}c[maxn];
LL dp[maxn];
inline bool cmp1(const node &A,const node &B){ return A.t<B.t; }
inline bool cmp2(const node &A,const node &B){ return A.r<B.r; }
int q[maxn];
LL x[maxn],y[maxn];
int main(){
int T;
for(scanf("%d",&T);T--;){
LL ans = 1ll<<60;
scanf("%d%d%d",&n,&tc[0],&tc[1]);
for(int i=1;i<=n;i++)
scanf("%d%d",&a[i].tp,&a[i].t),a[i].r=a[i].t+tc[--a[i].tp];
sort(a+1,a+1+n,cmp1);
for(int i=1;i<=n;i++) b[i] = a[i];
for(int i=1,j=1;i<=n;i++){
for(;j<=n && b[j].t <= a[i].t;j++);
a[i].L = j-1;
}
sort(a+1,a+1+n,cmp2);
for(int i=1,j=1;i<=n;i++){
for(;j<=n && b[j].t <= a[i].r;j++);
a[i].R = j-1;
}
for(int i=1;i<=n;i++)
sump[i][0] = sump[i-1][0] , sump[i][1] = sump[i-1][1],
sumt[i][0] = sumt[i-1][0] , sumt[i][1] = sumt[i-1][1],
sump[i][b[i].tp] ++ , sumt[i][b[i].tp] += b[i].t;
for(int i=1;i<=n;i++){
dp[i] = sump[a[i].R][a[i].tp^1] * a[i].r - sumt[a[i].R][a[i].tp^1];
}
for(int s=1;s<=n;s++){
int m = 1;
c[m].L=a[s].L,c[m].R=a[s].R,c[m].r=a[s].r,c[m].tp=a[s].tp;
for(;sump[c[m].R][c[m].tp^1]^sump[c[m-1].L][c[m].tp^1];){
m++;
c[m].L = c[m-1].R , c[m].R = c[m].L , c[m].tp = c[m-1].tp^1 , c[m].r = c[m-1].r + tc[c[m].tp];
for(;c[m].R <= n && b[c[m].R].t <= c[m].r;c[m].R++);
c[m].R--;
}
c[1].dp=dp[s];
for(int i=2;i<=m;i++){
c[i].dp = c[i-1].dp + (sump[c[i].R][c[i].tp^1] - sump[c[i-1].L][c[i].tp^1]) * c[i].r - sumt[c[i].R][c[i].tp^1] + sumt[c[i-1].L][c[i].tp^1];
if(sump[c[i].L][c[i].tp] == sump[n][c[i].tp]) ans = min(ans , c[i].dp);
}
for(int tp=0;tp<2;tp++)
for(int i=s+1,j=1,L=0,R=0;i<=n;i++){
if(a[i].tp==tp) continue;
for(;j<=m && c[j].r<=a[i].t;j++)
if(c[j].tp==tp){
x[j] = sump[c[j].L][c[j].tp] , y[j] = sumt[c[j].L][c[j].tp] + c[j].dp;
for(;L<R-1 && (x[q[R-1]]-x[q[R-2]])*(y[j]-y[q[R-2]])-(x[j]-x[q[R-2]])*(y[q[R-1]]-y[q[R-2]]) <= 0;R--);
q[R++] = j;
}
for(;L<R-1 && (x[q[L+1]]-x[q[L]])*a[i].r-(y[q[L+1]]-y[q[L]]) >= 0;L++);
if(L<R)
dp[i] = min(dp[i],c[q[L]].dp + (sump[a[i].R][c[q[L]].tp] - sump[c[q[L]].L][c[q[L]].tp]) * a[i].r - sumt[a[i].R][c[q[L]].tp] + sumt[c[q[L]].L][c[q[L]].tp]);
}
}
for(int i=1;i<=n;i++){
if(sump[a[i].L][a[i].tp] == sump[n][a[i].tp])
ans = min(ans , dp[i]);
}
printf("%lld\n",ans);
}
}