2019年CSP-J第二轮认证,第二题公交换乘。
题目链接:http://47.110.135.197/problem.php?id=5077。
著名旅游城市 B 市为了鼓励大家采用公共交通方式出行,推出了一种地铁换乘公交车的优惠方案:
现在你得到了小轩最近的公共交通出行记录,你能帮他算算他的花费吗?
输入文件的第一行包含一个正整数 n,代表乘车记录的数量。
接下来的 n 行,每行包含 3 个整数,相邻两数之间以一个空格分隔。第 i 行的第 1 个整数代表第 i 条记录乘坐的交通工具,0 代表地铁,1 代表公交车;第 2 个整数代表第 i 条记录乘车的票价 pricei ;第三个整数代表第 i 条记录开始乘车的时间 ti(距 0 时刻的分钟数)。
我们保证出行记录是按照开始乘车的时间顺序给出的,且不会有两次乘车记录出现在同一分钟。
输出文件有一行,包含一个正整数,代表小轩出行的总花费。
6
0 10 3
1 5 46
0 12 50
1 3 96
0 5 110
1 6 135
36
对于 30% 的数据, n ≤ 1000,ti ≤ 10^6。
另有 15% 的数据, ti ≤ 10^7,pricei 都相等。
另有 15% 的数据, ti ≤ 10^9 ,pricei 都相等。
对于 100% 的数据, n ≤ 10^5 ,ti ≤ 10^9,1 ≤ pricei ≤ 1000。
一个非常直白的题目,仔细读一下就知道含义。基本思路这样:根据乘车类型进行处理。如果是地铁,哪肯定是要付钱的,并吧这个记录保存下来。如果是公交车,遍历一下乘地铁的bonus队列,是否有满足需求的免费,如果有不需要付钱,如果没有那就付钱。
下面我们分析一下数据:100%的数据量可能达到10^5,也就是10万条。假设每次都需要买票,哪么累计的总价格将是1000*10^5,也就是10^8,用int可以满足。
根据数据规模和约定,我们知道,最坏的可能应该是这样,10^5个数据,前面10^5-1数据都是做地铁,最后一个公交车。哪么最大要遍历10^5-1次。
本题的难点在于:70%的数据 n ≤ 10^5,遍历免费的队列的时间复杂度要控制好,否则比较容易TLE。
要特别注意几个细节:
1、tbus − tsubway ≤ 45,这个如何在代码中表达和处理?意味着,队列里所有超过45分钟的数据要删除。
2、搭乘公交车时,如果可以使用优惠票一定会使用优惠票;如果有多张优惠票满足条件,则优先消耗获得最早的优惠票。意味着这是一个FIFO队列。
这样我们可以发现这个数据结构的特点:
1、FIFO
2、可以任意位置删除。
因此,最符合的数据结构类型为链表,可以考虑使用STL中的list来描述。由于本例特殊,所有的数据都是按照时间来排列的,因此使用STL的queue也是可以的。
不会STL的list,用数组来表示也可以,开一个10^5大小数组保存,不过要附加一个标志位,用来表示这个bonus是否已经使用。然后每次都是从 0 到 n 搜索。
由于没有完整的测试数据,不能保证下面代码100%可以AC。但是已经在某谷测试通过。
#include
#include
struct BONUS {
int price;//价格
int time;//时间
BONUS() : price(0), time(0) {}
BONUS(int p, int t) : price(p), time(t) {}
};
int main() {
freopen("transfer.in", "r", stdin);
freopen("transfer.out", "w", stdout);
int n;
scanf("%d", &n);
unsigned long long ans = 0;
std::list
int i;
int t_old = 0;
for (i=0; i
int price;//价格
int time;//时间
scanf("%d %d %d", &type, &price, &time);
if (0==type) {
//地铁.
//将获得等价的优惠券
ans += price;
bonus.push_back(BONUS(price, time));
} else if (1==type) {
//公交车
//查看是否有优惠券使用
std::list
bool flag=false;
for (it=bonus.begin(); it!=bonus.end();) {
//判断时间
if (time - it->time <= 45) {
//判断价格
if (it->price >= price) {
//使用优惠券
bonus.erase(it++);
flag=true;
break;
} else {
it++;
}
} else {
//超时,删除
bonus.erase(it++);
}
}
if (false==flag) {
//无法优惠
ans += price;
}
}
}
printf("%llu\n", ans);
fclose(stdin);
fclose(stdout);
return 0;
}