飙车race

8 篇文章 0 订阅
1 篇文章 0 订阅

飙车race

【题目描述】

最近,Lucas 参加了一个飙车比赛。比赛在环型赛道上进行,全程共 K 圈。在比赛中,选手需要用主办方提供的赛车,而这种老爷车给 Lucas 带来了巨大的麻烦。这种赛车的油箱可以装 n 个单位的油。每个单位的油可以支持赛车跑恰好 1 圈。每圈开始前,你需要保证你的油箱里的油量是一个正整数。一圈跑完后,油箱里的油会减少恰好 1 个单位。每一开始前,你可以进入加油站进行加油,一次加油的耗时是一个固定的常数 P。每次加油时你可以把油量加至任意你想要的整数。特别地,如果开始一圈时剩余油量恰好为 1,这也是允许的:结束这一圈时剩余油量为 0,此时你必须进站加油,除非你恰好跑完最后一圈。
比赛开始前,你也可以进行加油,这次加油不会被计入比赛时间。赛车在不同油量下的速度是不同的。经过测试,如果一圈开始时油箱中剩余的油量为 i 单位,则跑完这圈需要 ti单位时间。当然,符合常识的是,油箱里的油越多,车就跑得越慢,所以我们保证 ti <= ti+1 。作为一名老司机,Lucas 自然会参加很多场比赛。他共参加了 Q 场比赛,每场比赛

都有一个独立的 K 和 P。请你帮 Lucas 的粉丝 Yazid 求出每场比赛 Lucas 的最短比赛用时。


由于题意难以描述,在此只好附上题目...

第一行两个正整数n,Q表示油箱大小和比赛场数

n个正整数t1,t2...tn表示油箱大小为1至n时,赛车跑一圈要用的时间。

接下来Q行,每行两个正整数K,P,描述这场比赛。



哎一言难尽啊,作为T3,部分分怎么能给的这么少?!蒟蒻表示少得可怜啊...然后就打炸了。

30分应该可以用DP乱搞,其他还有10分P=1的部分分。

60分用n^2的贪心,100分就要用到三分法加贪心啦...真心不容易qwq。

先讲n^2贪心,100分只要加一个三分即可。

n^2的算法,显而易见,如果一个决策是最优的,那么每次加油都应该加这个决策的油量,如果还有剩余就平均分配到前面的几次中,每次多加一个单位的油,这个贪心想到后面就很简单辣。

枚举每一次加的油量,就能O(1)的时间内算出需要花费的时间。总时间复杂度O(Qn)就能拿到60分。



至于100分,应该可以发现这样决策的函数是单峰的,简单的想一下,太左边不是最优的,太右边也不是最优的,具体证明其实我也只知道一点点qwq...那就不证了,可这竟然是我打的第一道三分,真是道好题真的。



#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#define ll long long
#define N 200000+2000
using namespace std;
int n,Q;
ll s[N],t[N],ans1,ans2,ans,mid1,mid2,K,P;
ll calc(int x){
	ll sum=K/x;
	ll sum2=K-sum*x;
	ll sum1=x-sum2; 
	return sum1*s[K/x]+sum2*s[K/x+1]+P*(x-1);
}
ll read(){
	ll num=0;char ch=getchar();
	while (ch>='0' && ch<='9') num=num*10+ch-'0',ch=getchar();
	return num;
}
int main()
{
	freopen("race.in","r",stdin);
	freopen("race.out","w",stdout);
	n=read();Q=read();
	for(int i=1;i<=n;i++) t[i]=read();
	for(int i=1;i<=n;i++) s[i]=s[i-1]+t[i];
	while(Q--){
		K=read(),P=read();
		ans=1e9*1e9;
		ll l=(K-1)/n+1,r=K;
		while(l<=r){
			mid1=(l+r)>>1;mid2=mid1+1;
			if(mid2>r) mid2=r;
			ans1=calc(mid1);ans2=calc(mid2);
			if(ans1>ans2) l=mid1+1;
			else if(ans1<ans2) r=mid2-1;
			else{
				l=mid1+1;r=mid2-1;
				ans=ans1;
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值