河南省第十二届ACM省赛-D地铁1号线

 看到省赛的原题已经上传至NYOJ了,准备重温一下

 

某市1号地铁线, 每天6:00 从始发站发出第一趟地铁,以后每隔 m 分钟发出下一趟,直到晚上22:00发出当日最后一趟地铁。

经过运行 X 年的数据分析发现,每趟地铁的车票收入与它的起发时间有一定关联。比如:6:00发出的地铁,由于坐车人数少,一趟下来车票收入为4.50千元;8:00发出的地铁,由于坐车人多,一趟下来车票收入为12.00千元。不同段时间内起发的地铁,车票收入满足不同的线性关系。

输入描述:

第一行: T表示以下有T组测试数据( 1≤ T ≤ 8 )
对每组数据,第1行有两个整数 m  n ,接下来有n行,每行两个数据,格式为:  hh:mm  x  分别表示发车时间和车票收入。其中:  10≤ m ≤ 60  1 ≤ n ≤ 100      0.00 ≤ x ≤ 100000.00

输出描述:

对每组测试数据,输出一个实数,1号地铁线一天的车票总收入。(精确到小数点后2位)

样例输入:

1
60  3
06:00  4.50
08:00  12.00
22:00  12.00

样例输出:

192.75

 

这题有个挖坑的地方就是6点和12点不一定是发车始终时间,发车始终时间需要从输入数据中获取,分别是最小和最大时间点。

关于收益,如果在输入的时间点上,那么收益就是对应的输入数据。对于不在时间点上的收益,可以采用斜率计算,比如样例中

06:00(4.50)到08:00(12.00)之间存在时间点7:00发车,转换成分钟就是420分发车,位于360与480分钟的区间,收益计算为

4.50+(420-360)*(12.00-4.50)/(480-360),这类似于给定两点求出一次函数,然后计算其中某点的函数值f(x)。

 

代码如下:

#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
using namespace std;
void slove(int step,int time){
	vector<int> vec;//保存时间点
	map<int,double> mp;//时间点和费用映射关系
	for(int i=0;i<time;i++){//输入
		int h,m;
		double mon;
		scanf("%d:%d",&h,&m);
		cin>>mon;
		vec.push_back(h*60+m);
		mp[h*60+m]=mon;
	}
	sort(vec.begin(),vec.end());//时间点排序
	
	double fee=0.0;//总收益
	int base=0;//时间所在区间标记
	for(int i=vec[0];i<=vec[time-1];i+=step){
		if(base<time-1){//标记判断
			if(i>vec[base+1]){
				base++;
			}
		}
		if(i==vec[base]){//位于标记头则费用增加
			fee+=mp[vec[base]];
			cout<<i<<endl;
		}else{
			double a=mp[vec[base+1]]-mp[vec[base]],b=vec[base+1]-vec[base],len=i-vec[base];//斜率算费用
			fee+=mp[vec[base]]+(a/b)*len;
		}
	}
	printf("%.2f\n",fee);
}
int main()
{
	int n;
	cin>>n;
	while(n--){
		int step,time;
		cin>>step>>time;
		slove(step,time);
	}
	return(0);
}

 tips:NYOJ这题的样例似乎是传错了,导致这题无法AC(但是算法可以保证是对的,因为比赛现场这题我通过了)

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cout0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值