小Z的 AK 计划 洛谷p2147

本文介绍了一个算法问题,小Z要在有限时间内访问机房街上的多个机房并完成尽可能多的ACM题目。通过使用贪心算法和优先队列实现最优方案。

题目描述

在小Z的家乡,有机房一条街,街上有很多机房。每个机房里都有一万个人在切题。小Z刚刷完CodeChef,准备出来逛逛。

机房一条街有 n 个机房,第 i 个机房的坐标为 xi ,小Z的家坐标为 0。小Z在街上移动的速度为1,即从 x1 到 x2 所耗费的时间为 |x1 − x2|。每个机房的学生数量不同,ACM 题目水平也良莠不齐。小Z到达第 i 个机房后,可以花 ti 的时间想题,然后瞬间 AK;当然,也可以过机房而不入。

小Z现在只有 m 个单位时间,之后他就该赶着去打 Codeforces 了。现在他想知道自己最多能在多少个机房 AK,希望你帮帮他。
输入输出格式
输入格式:

第一行包含两个整数 n,m。

接下来 n 行,每行包含两个整数 xi,ti 。
输出格式:

第一行包含一个整数,表示小Z最多能 AK 的机房数量。
输入输出样例
输入样例#1:

2 10
1 100
5 5

输出样例#1:

1

说明

【数据规模】

对于 30% 的数据,n ≤ 20。

对于 60% 的数据,n ≤ 1000。

对于 100% 的数据,1 ≤ n ≤ 10^5,0 ≤ m,xi ≤ 10^18,0 ≤ ti ≤ 10^9。

设二元组f[i]表示当前走到了第i个机房时,剩余多少时间,最多能ak多少题,STA表示选择ak的机房的集合(包括第i个),定义二元组运算,状态转移方程为:
dp
表示如果时间本身就够,那么X可为空集,|x|=0,ak的题就加1,如果时间不够,那就需要在已选择ak的机房中去掉一部分来腾出时间,ak的题的数量就加上(1-去掉的机房数),在二元组运算过程中,剩余时间要保证>=0,最后答案为f[i]在i取1~n中的最大值,可是每次转移的代价太大,因此考虑优化。
由于每个机房都只能ak一次,所以考虑贪心,每次去掉耗时最大的机房,直到时间不超,这样可以用堆来维护选择ak的机房集合。
因为每个机房只会进堆一次出堆一次,所以时间复杂度为O(nlogn)。

#include<iostream>
#include<algorithm>
#define f(i,l,r) for(i=(l);i<=(r);i++)
using namespace std;
const int MAXN=100005;
struct Bar{
    long long x;
    int t;
    bool operator < (const Bar& X)const{
        return x<X.x;
    }
}a[MAXN];
int n,ans=0,sz;
long long m,sum,res;
long long heap[MAXN];
inline void pushup(int p)                   //堆的基本操作 
{
    int fa=p>>1,a=heap[p];
    while(fa&&a>heap[fa]){
        heap[p]=heap[fa];
        p=fa;
        fa>>=1;
    }
    heap[p]=a;
}
inline void pushdown(int p)
{
    int son=p<<1,a=heap[p];
    while(son<=sz){
        if(son<sz&&heap[son+1]>heap[son]) son++;
        if(a>=heap[son]) break;
        heap[p]=heap[son];
        p=son;
        son<<=1;
    }
    heap[p]=a;
}
inline void insert(int a)
{
    heap[++sz]=a;
    pushup(sz);
}
inline void Pop()
{
    heap[1]=heap[sz--];
    pushdown(1);
}
int main()
{
    ios::sync_with_stdio(false);         //关闭流同步 
    int i,j;
    cin>>n>>m;
    f(i,1,n){
        cin>>a[i].x>>a[i].t;
    }
    sort(a+1,a+1+n);
    f(i,1,n){
        res=m-a[i].x;                 //能分配给做题的时间 
        if(res<0) break;
        sum+=a[i].t;                  //做题的总时间 
        insert(a[i].t);               //将要做的题加入堆中 
        if(res-sum>=0){               //如果能分配的时间足够  
            ans=max(ans,sz);          
        }
        else{
            while(res-sum<0){         //根据贪心,每次把耗时最大的去掉,知道时间够 
                sum-=heap[1];
                Pop();
            }
            ans=max(ans,sz);          //更新答案 
        }
    }
    cout<<ans<<endl;
    return 0; 
}
### 关于平台中的 “Ak” 在平台上,“Ak” 是一种常见的表示方式,通常用于描述算法竞赛题目中的输入数据结构或者特定变量的定义。具体到引用的内容中提到的形式 `K A1 C1 A2 C2 ... Ak Ck`[^4],可以推测这的“Ak”代表的是某种序列或数组的一部分。 #### 结合上下文分析 根据引用内容提及的“接龙数列”的定义[^3],即一个长度为 $ K $ 的整数数列满足条件:$ Ai $ 的首位数字恰好等于 $ Ai-1 $ 的末位数字(其中 $ 2 \leq i \leq K $),可以看出: - 数字 $ K $ 表示整个数列的长度。 - 序列中的每一项可以用 $ A_i $ 来表示,而这些 $ A_i $ 就构成了所谓的“接龙数列”。 因此,在这种情况下,“Ak” 可能是指该数列的最后一项或者是第 $ k $ 个元素的具体数值。 另外,从另一个角度考虑,如果参照合法文本文件的例子[^2],我们可以发现类似的数据排列模式也可能适用于其他类型的字符串处理问题。不过需要注意的是,这并没有直接涉及数学复杂度概念如 $ O(n\log n) $[^1],所以不必过多纠结于此方面。 综上所述,“Ak” 主要是在描述一系列按照一定规则构建起来的对象集合的某个成员位置标记或是实际值本身。 ```python # 示例代码展示如何解析可能包含"Ak"形式的数据 def parse_sequence(input_data): parts = input_data.split() k_value = int(parts[0]) # 获取K值 sequence = [] for index in range(1, len(parts), 2): a_part = int(parts[index]) c_part = parts[index + 1] sequence.append((a_part, c_part)) return sequence[:k_value] example_input = "3 1 X 2 Y 3 Z" parsed_result = parse_sequence(example_input) print(parsed_result) ``` 上述代码片段展示了如何基于给定格式提取出类似于“Ak”这样的成分及其关联部分的信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值