CSP-J 2019 T2 公交换乘(洛谷P5661
CSP-J 2019 T2 公交换乘
思路
还不错的一道模拟,我们读完题很容易想出记录所有的票然后一个一个判断,遇到地铁票就存起来准备坐公交的时候用,然后遇到公交就判断目前所有的地铁票是否满足要求。不过这样时间复杂度太高了,因为每张票的时间都是比上一张票时间靠后的,所以我们设地铁票为\(a_1, a_2, a_3, a_4, a_5\),如果\(a_4\)的时间不满足要求的话(超出了45分钟的范围)那\(a_1,a_2,a_3\)肯定也是不满足要求的,而且对于之后的票也肯定是不满足的,我们可以直接丢掉这些票。
我们用一个结构体来存票的时间\(s\)、价格\(p\)和种类\(k\),\(ts\)表示所有的票,\(q\)表示所有的地铁票。
判断优惠券能不能用
有点类似于单调队列,用\(h\)表示最早的能用的地铁票(也就是优惠券)的下标,每遇到一个公交就往后推,清掉所有不满足要求的优惠券。
while(ts[i].s-q[h].s>45&&h<=t) ++h;
// 判断时间是否符合范围 判断还有没有优惠券
//不符合范围就找下一张并把当前这张丢掉
然后在清掉所有时间不满足要求的优惠券之后我们去找到最早的那张价格满足要求的,因为有可能之后会有价格更低的公交票需要用优惠券,所以我们在找价格符合要求的优惠券的时候不用丢掉价格不符合要求的优惠券。
把for循环用的变量\(j\)定义到循环外面,这样循环结束或者找到满足要求的优惠券\(\operatorname{break}\)出来时可以方便的找到符合的下标。将用过的优惠券的价格定为一个负数,这样相当于删除,因为这张优惠券的价格不会大于等于任何公交票的价格。
int j;
for(j=h;j<=t;++j){
if(q[j].p>=ts[i].p) break;
//如果优惠券的价格大于等于公交票的价格就是找到了,直接用就行
}
if(j>t){
ans+=ts[i].p;
//如果j大于t那就是找了所有的优惠券都没有满足要求的
}
else{
q[j].p=-1;
}
代码
#include <iostream>
#include <cstdio>
using namespace std;
inline int read(){
int x=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
x=(x<<3)+(x<<1)+(c^48);
c=getchar();
}
return x*f;
}
inline void write(int x){
if(x<0){x=-x;putchar('-');}
if(x>9) write(x/10);
putchar(x%10+'0');
}
struct ticket
{
int s,p,k;
}ts[100005],q[100005];
int n,h=1,t,ans;
int main()
{
n=read();
for(int i=1;i<=n;++i){
ts[i].k=read();
ts[i].p=read();
ts[i].s=read();
if(ts[i].k==0){
q[++t]=ts[i];
ans+=ts[i].p;
continue;
}
while(ts[i].s-q[h].s>45&&h<=t) ++h;
if(h>t){
ans+=ts[i].p;
continue;
}
else{
int j;
for(j=h;j<=t;++j){
if(q[j].p>=ts[i].p) break;
}
if(j>t){
ans+=ts[i].p;
}
else{
q[j].p=-1;
}
}
}
write(ans);
return 0;
}