CF187D 题解

模拟考最后一题是这道题,要是数组开大就场切了,最后不小心挂了 \(15\) 分。

以下是考场思路:

考虑这样一个问题,所有时间对 \(r+g\) 取余是可以的。毕竟红绿灯是一个循环。

再考虑这样一个东西,等过一次红灯后的所有情况是相似的,从循环的角度出发都是时刻 \(0\)

因此考虑处理出出发之后第一次遇到红绿灯的点,然后问题就变成从一个路口到终点,可以使用一次 \(n^2\) 的 dp 完成。

接下来先考虑如何处理第一次遇到红绿灯的点。

假若需要从之前的路口走到这个路口需要花费时间 \(x\) 那么满足以下条件的出发时间 可能 会在这个点第一次遇到红绿灯。

\[t + x < g (\bmod (r+g)) \]

第一次遇到红绿灯的点就是最小的 \(x\)

实际上满足条件的 \(t\) 根据与 \(g\) 的大小关系构成至多两段区间,考虑动态开点权值线段树维护区间取最小值和单点查询。

接下来考虑如何优化上面那个 \(n^2\) 的 dp 我们可以发现等完红绿灯出发与从起点出发的情况实际上是类似的,倒着扫描一遍且与上面那种情况类似的用线段树维护即可。

注意空间不要开小了。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e5+114;
const int inf = 1e9+114;
int tr[maxn*70+1],tag[maxn*70+1],ls[maxn*70+1],rs[maxn*70+1],tot; 
long long l[maxn],pre[maxn],dp[maxn];
long long cost[maxn];
long long G,R,n,q;
void pushdown(long long cur){
	if(ls[cur]==0) ls[cur]=++tot;
	if(rs[cur]==0) rs[cur]=++tot;
	tr[ls[cur]]=min(tr[ls[cur]],tag[cur]);
	tr[rs[cur]]=min(tr[rs[cur]],tag[cur]);
	tag[ls[cur]]=min(tag[ls[cur]],tag[cur]);
	tag[rs[cur]]=min(tag[rs[cur]],tag[cur]);
	tag[cur]=inf;
}
void pushup(long long cur){
	tr[cur]=min(tr[ls[cur]],tr[rs[cur]]);
}
void update(int &cur,long long lt,long long rt,long long l,long long r,int v){
	if(lt>rt) return ;
	if(l>rt||r<lt) return;
	if(cur==0) cur=++tot;
	if(l<=lt&&rt<=r){
		tr[cur]=min(tr[cur],v);
		tag[cur]=min(tag[cur],v);
		return ;
	}
	long long mid=(lt+rt-1)>>1;
	pushdown(cur);
	update(ls[cur],lt,mid,l,r,v);
	update(rs[cur],mid+1,rt,l,r,v);
	pushup(cur);
}
long long query(long long cur,long long lt,long long rt,long long l,long long r){
	if(l>rt||r<lt||cur==0) return inf;
	if(l<=lt&&rt<=r) return tr[cur];
	long long mid=(lt+rt-1)>>1;
	pushdown(cur);
	return min(query(ls[cur],lt,mid,l,r),query(rs[cur],mid+1,rt,l,r));
}
int rt;
void init(){
	for(long long i=1;i<=n;i++) pre[i]=(pre[i-1]+l[i])%(G+R),cost[i]=cost[i-1]+l[i];
	for(long long i=0;i<maxn*70;i++) tr[i]=tag[i]=inf;
	dp[n+1]=0;
	for(int i=n;i>=1;i--){
		long long x=(G+R-pre[i])%(G+R);
		long long y=query(rt,0,G+R-1,(x)%(G+R),(x)%(G+R));
		if(y<inf) dp[i]=dp[y]+(cost[y]-cost[i]+((G+R)-((cost[y]-cost[i])%(G+R))));
		else dp[i]=cost[n]-cost[i]+l[n+1];
		if(pre[i]<=G){
			update(rt,0,G+R-1,G-pre[i],R+G-1-pre[i],i);
		}
		else{
			update(rt,0,G+R-1,0,R+G-1-pre[i],i);
			update(rt,0,R+G-1,G+R-pre[i]+G,R+G-1,i);
		}
	}
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n>>G>>R;
	for(long long i=1;i<=n+1;i++) cin>>l[i];
	init();
	cin>>q;
	while(q--){
		long long x;
		cin>>x;
		long long st=query(rt,0,G+R-1,x%(G+R),x%(G+R));
		if(st==inf){
			cout<<x+cost[n]+l[n+1]<<'\n';
		}
		else{
			long long res=cost[st]+x+((G+R)-((cost[st]+x)%(G+R)));
			res+=dp[st];
			cout<<res<<'\n';
		}
	}
	return 0;
}
/*
4 5 1
12 18 4 6 7
5
4
11
5
3
2
*/
posted @ 2024-01-30 23:52  ChiFAN鸭  阅读(18)  评论(0编辑  收藏  举报