P3697 题解

P3697

思路

贪心。

首先,不加快车时,能到达的车站应跟在特急车停的站之后。即对于 \(s_i\)\(s_{i+1}\) 之间的 \(j\),如果 \(j\) 可以到达,从 \(s_i\)\(j\) 的站都符合条件。

再考虑快车。

对于一个站,最快的到达方式是:先坐特急车到最近的站点,再坐快车到最近的站点,最后转慢车。这样 \(m\) 个特急车停靠的站点将整条线路分成 \(m-1\) 段,分别处理。

在一段之内,从 \(s_i\) 出发只坐慢车最远可以到 \(pos_1\),自身贡献 \(pos_1-s_i+1\) 个站。如果要在这一段增设快车站,最优是设在 \(pos_1+1\) 处,最远能到 \(pos_2\),贡献 \(res_2\)\(pos_2-pos_1\)。以此类推。直到有 \(pos_k \ge s_{i+1}\) 为止。

这样,每段会有一定数量的可以设快车站的点,分别有一定贡献。用优先队列,选出前 \(k\) 大贡献即可。

可能会找出很多个贡献为 \(1\) 的点并入队而后面是不需要那么多的。又可以发现,在 每一段中,设置车站的贡献单调不增。所以,对于每一段,只需要入队前 \(k\) 个贡献。

int n,m,k,a,b,c,t;
int pos,res,cnt,ans;
int s[maxn];
priority_queue <int> q;

signed main(){
	scanf("%lld%d%d",&n,&m,&k);
	k-=m;
	scanf("%lld%lld%lld%lld",&a,&b,&c,&t);
	for(int i=1;i<=m;i++)scanf("%lld",&s[i]);
	for(int i=1;i<m;i++){
//		cout<<i<<" "<<s[i]<<endl;
		pos=s[i];cnt=0;
		while(pos<s[i+1]){
			++cnt;
			if(t-(s[i]-1)*b-(pos-s[i])*c<0)break;
			res=(t-(s[i]-1)*b-(pos-s[i])*c)/a+1;
			if(pos+res>=s[i+1]){
				res=s[i+1]-pos;
				pos=s[i+1];
			}
			pos+=res;
			if(cnt==1){
				ans+=res;
//				cout<<ans<<endl;
			}
			else{
				q.push(res);
//				cout<<res<<endl;	
			}
			if(cnt>k+1)break;
//			cout<<res<<" "<<pos<<endl;
		}
	}
	if(t>=(n-1)*b)ans++;
//	cout<<ans<<endl;
	while(!q.empty() && k){
		k--;
		ans+=q.top();
		q.pop();
//		cout<<ans<<endl;
	}
	printf("%lld",ans-1);
}
posted @ 2024-05-10 20:03  yhddd  阅读(12)  评论(0)    收藏  举报