惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

小众软件
小众软件
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
WordPress大学
WordPress大学
月光博客
月光博客
Hugging Face - Blog
Hugging Face - Blog
博客园 - 聂微东
博客园 - 【当耐特】
博客园_首页
The Cloudflare Blog
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Apple Machine Learning Research
Apple Machine Learning Research
Last Week in AI
Last Week in AI
酷 壳 – CoolShell
酷 壳 – CoolShell
大猫的无限游戏
大猫的无限游戏
雷峰网
雷峰网
量子位
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
Tailwind CSS Blog
IT之家
IT之家
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
GbyAI
GbyAI
V
Visual Studio Blog
F
Fortinet All Blogs
Martin Fowler
Martin Fowler

Ariasakaの小窝

Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝 Ariasakaの小窝
Ariasakaの小窝
2022-11-28 · via Ariasakaの小窝

前往以下网站,不保证安全性哦喵~P5661 [CSP-J2019] 公交换乘洛谷

一道橙题,但是会T。

题面

查看题目

[CSP-J2019] 公交换乘

题目描述

著名旅游城市 B 市为了鼓励大家采用公共交通方式出行,推出了一种地铁换乘公交车的优惠方案:

  1. 在搭乘一次地铁后可以获得一张优惠票,有效期为 45 分钟,在有效期内可以消耗这张优惠票,免费搭乘一次票价不超过地铁票价的公交车。在有效期内指开始乘公交车的时间与开始乘地铁的时间之差小于等于 45 分钟,即: $t{bus} - t{subway} \leq 45$
  2. 搭乘地铁获得的优惠票可以累积,即可以连续搭乘若干次地铁后再连续使用优惠票搭乘公交车。
  3. 搭乘公交车时,如果可以使用优惠票一定会使用优惠票;如果有多张优惠票满足条件,则优先消耗获得最早的优惠票。

现在你得到了小轩最近的公共交通出行记录,你能帮他算算他的花费吗?

输入格式

输入文件的第一行包含一个正整数 $n$,代表乘车记录的数量。

接下来的 $n$ 行,每行包含 3 个整数,相邻两数之间以一个空格分隔。第 $i$ 行的第 1 个整数代表第 $i$ 条记录乘坐的交通工具,0 代表地铁,1 代表公交车;第 2 个整数代表第 $i$ 条记录乘车的票价 $price_i$ ;第三个整数代表第 $i$ 条记录开始乘车的时间 $t_i$(距 0 时刻的分钟数)。

我们保证出行记录是按照开始乘车的时间顺序给出的,且不会有两次乘车记录出现在同一分钟。

输出格式

输出文件有一行,包含一个正整数,代表小轩出行的总花费。

样例 #1

样例输入 #1

TEXT
6
0 10 3
1 5 46
0 12 50
1 3 96
0 5 110
1 6 135

样例输出 #1

TEXT
36

样例 #2

样例输入 #2

TEXT
6
0 5 1
0 20 16
0 7 23
1 18 31
1 4 38
1 7 68

样例输出 #2

TEXT
32

提示

【输入输出样例 1 说明】

第一条记录,在第 3 分钟花费 10 元乘坐地铁。

第二条记录,在第 46 分钟乘坐公交车,可以使用第一条记录中乘坐地铁获得的优惠票,因此没有花费。

第三条记录,在第 50 分种花费 12 元乘坐地铁。

第四条记录,在第 96 分钟乘坐公交车,由于距离第三条记录中乘坐地铁已超过 45 分钟,所以优惠票已失效,花费 3 元乘坐公交车。

第五条记录,在第 110 分钟花费 5 元乘坐地铁。

第六条记录,在第 135 分钟乘坐公交车,由于此时手中只有第五条记录中乘坐地铁获得的优惠票有效,而本次公交车的票价为 6 元,高于第五条记录中地铁的票价 5 元,所以不能使用优惠票,花费 6 元乘坐公交车。

总共花费 36 元。

【输入输出样例 2 说明】

第一条记录,在第 1 分钟花费 5 元乘坐地铁。

第二条记录,在第 16 分钟花费 20 元乘坐地铁。

第三条记录,在第 23 分钟花费 7 元乘坐地铁。

第四条记录,在第 31 分钟乘坐公交车,此时只有第二条记录中乘坐的地铁票价高于本次公交车票价,所以使用第二条记录中乘坐地铁获得的优惠票。

第五条记录,在第 38 分钟乘坐公交车,此时第一条和第三条记录中乘坐地铁获得的优惠票都可以使用,使用获得最早的优惠票,即第一条记录中乘坐地铁获得的优惠票。

第六条记录,在第 68 分钟乘坐公交车,使用第三条记录中乘坐地铁获得的优惠票。

总共花费 32 元。

【数据规模与约定】

对于 $30%$ 的数据,$n \leq 1000$,$t_i \leq 10^6$。

另有 $15%$ 的数据,$t_i \leq 10^7$,$price_i$ 都相等。

另有 $15%$ 的数据,$t_i \leq 10^9$,$price_i$ 都相等。

对于 $100%$ 的数据,$n \leq 10^5$,$t_i \leq 10^9$,$1 \leq price_i \leq 1000$。

PS:其实你可以点这个复制而不用慢慢改格式qaq

解析

很明显,这道题只需要使用一个结构体数组来模拟门票,如果时间在$45$ 分钟内,即$ticket_{time} \leq time_i$,且 $ticket_{price} \leq price_i$,且满足 ticket.can (票可以用)这三个条件即可,因为要求优先消耗获得最早的优惠票,所以从最前面开始查找就行了。

于是,你很轻易地写出了这个代码:

CPP
#include <bits/stdc++.h>
using namespace std;
struct ticket{
    int time;
    int price;
    bool can=1;
};
inline void read(int &n){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar(); //PS:不用快读可能炸
    }
    n=x*f;
}
int main(){
//    freopen("P5661_9.in","r",stdin);
//    freopen("P5661_9.ans","w",stdout); 
    int n,s=0,l=1;
    ticket t[114514];
    read(n);
    for(int i=1;i<=n;i++){
        int b,tim,p;
        read(b);read(p);read(tim);
        if(b==0){
            t[l].time=tim;
            t[l].price=p;
            l++;
            s+=p;
        }
        if(b==1){
            int flag=1;
            for(int j=1;j<l;j++){
                if(t[j].can&&t[j].price>=p&&tim-t[j].time<=45){
                    t[j].can=0;
                    flag=0;
                    break;
                }

            }
            if(flag){
                s+=p;
            }
        }
    }
    cout<<s;
    return 0;
}

恭喜你喜提 $35$ 分。

我们想想,所有的数据,$n \leq 10^5$,显然每次去搜索一遍表来找门票,时间复杂度必然是$O(n^2)$的,计算次数$n \leq 10^{25}$,绝对会超时。

怎么优化呢?我们想想,是不是每一次坐公交车的时候找票都只找没过期的票,是吧。因为时间是升序排列的,所以我们每一次找票的时候根本不需要在前面的一堆烂票里面浪费自己的美好年华。我们不如用一个变量 $X$ 来标记目前第一个没超时(注意不是没有用过)的票,每次找的时候从第 $X$ 张票开始找满足的就行了。

代码

我已经详细看完并理解了上面的内容,并且不会直接照搬
CPP
#include <bits/stdc++.h>
using namespace std;
struct ticket{
    int time; //时间
    int price; //价值
    bool can=1; //能不能用
}t[114514]; //结构体数组
inline void read(int &n){
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    } //PS:不用快读,甚至cin也能过,但40+ms的读入浪费,显然不太好
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    n=x*f;
}
int main(){
//    freopen("P5661_9.in","r",stdin);
//    freopen("P5661_9.ans","w",stdout); 
    int n,s=0,l=1,x=1;
    read(n);
    for(int i=1;i<=n;i++){
        int b,tim,p;
        read(b);read(p);read(tim);
        if(b==0){ //地铁,并且往数组里面扔一个票
            t[l].time=tim;
            t[l].price=p;
            l++;
            s+=p;
        }
        if(b==1){ //公交
            int flag=1; //用票与否
            for(int j=x;j<l;j++){
                if(t[j].can&&t[j].price>=p&&tim-t[j].time<=45){ //满足三个条件就能用
                    t[j].can=0;
                    flag=0; //用票
                    break; //找到能用的票就退出
                }
                if(tim-t[j].time>45){
                    x=j; //超时了前面的就不要了
                }
            }
            if(flag){
                s+=p; //不用票
            }
        }
    }
    cout<<s;
    return 0;
}