搜索专题
目录
- MT2238 数的增殖
- MT2239 二维矩阵中的最长下降序列
- MT2240 传染病
- MT2241 循环空间
- BD202303 第五维度
MT2238 数的增殖
难度:黄金 时间限制:1秒 占用内存:128M
题目描述
给定一个数 n ( n < 1000 ) n (n<1000) n(n<1000),可以按以下方法进行增殖:
- 取原数最高位,在左边加上不大于最高位一半的数;
- 不做处理。
现在问最多能生成多少个不同的数。
格式
输入格式:第一行输入一个正整数 n n n。
输出格式:一个正整数,表示最多能生成的数的个数。样例 1
输入:
5输出:
4备注
其中: n ≤ 10 3 n\le{10}^3 n≤103。
测试数据中生成了:
5→15
5→25→125
共4个数字(不计算重复数字)。
相关知识点:
深度优先搜索
题解
这道题按其意思进行模拟即可。定义两个函数:
函数一:取出当前数的最高位(循环取模实现)。
// 获取数的最高位值
int getHighestOrder(int n)
{
int highestOrder;
while(n){
highestOrder = n%10;
n /= 10;
}
return highestOrder;
}
函数二:对最高位的数 n n n 按要求进行处理,即在当前数 n n n 的前面添加一个数 m ( m ∈ [ 1 ∼ ⌊ n 2 ⌋ ] ) m\ (m\in\left[1\sim\left\lfloor\frac{n}{2}\right\rfloor\right]) m (m∈[1∼⌊2n⌋])。显然,函数二是一个递归调用的过程。一旦最高位数 n n n 的一半小于1时,整个过程就停止了(注:这种情况下,这个数本身应该要被算进去,因此要返回 1)。
// 获取数的增值
int getAddedValue(int n)
{
int addedValue = 1;
int halfHighestValue = getHighestOrder(n) / 2;
for(int i=1; i<=halfHighestValue; i++)
addedValue += getAddedValue(i);
return addedValue;
}
基于此,可得到求解本题的完整代码:
/*
MT2238 数的增值
搜索
*/
#include<bits/stdc++.h>
using namespace std;
// 获取数的最高位值
int getHighestOrder(int n)
{
int highestOrder;
while(n){
highestOrder = n%10;
n /= 10;
}
return highestOrder;
}
// 获取数的增值
int getAddedValue(int n)
{
int addedValue = 1;
int halfHighestValue = getHighestOrder(n) / 2;
for(int i=1; i<=halfHighestValue; i++)
addedValue += getAddedValue(i);
return addedValue;
}
int main( )
{
// 录入数据
int n;cin>>n;
// 输出数的增值
cout<<getAddedValue(n)<<endl;
return 0;
}
MT2239 二维矩阵中的最长下降序列
难度:钻石 时间限制:1秒 占用内存:128M
题目描述
给定一个 n × m n\times m n×m 的矩阵,然后可以随机选取一个点作为起始点,每次可以选择该点的上下左右四个相邻点中的一个并且保证相邻点的值小于当前点的值。问最长下降序列的长度是多少?
格式
输入格式:第一行输入两个正整数 n , m ( 1 ≤ n , m ≤ 100 ) n,\ m\ \left(1\le n,\ m\le100\right) n, m (1≤n, m≤100);
接下来 n n n 行,每行 m m m 个数字 a [ i ] [ j ] ( ( 1 ≤ a [ i ] [ j ] ≤ 4 × 10 4 ) ) a\left[i\right]\left[j\right]\ (\left(1\le a\left[i\right]\left[j\right]\le4{\times10}^4\right)) a[i][j] ((1≤a[i][j]≤4×104))。
输出格式:输出最长下降序列的长度。样例 1
输入:
5 4
1 2 3 4
16 17 18 19
15 24 25 20
14 23 22 21
13 12 11 10输出:
16备注
样例中,选取起始点 25,然后 25→24→23→……→11→10,长度为 16。
相关知识点:
深度优先搜索
、记忆化搜索
题解
题目的意思是在一个 n × m n\times m n×m 的矩阵中找一个位置,使得从该位置出发(只能往上、下、左、右四个方向行走,且下一个位置上的值必须小于当前位置上的值)能得到最长的路径长度。这是一道非常典型的DFS走迷宫问题。最简单粗暴的方式就是遍历整个矩阵中的全部位置,算出从该位置出发得到的最长路径长度。但遗憾的是,在题目给出的最广可达 100 × 100 100\times100 100×100 的数据范围下,这种办法肯定不能拿到满分。
注意到一个事,该办法超时的原因在于,每次基于某个位置进行深度优先搜索时,都有可能会出现重复计算。例如,下图中,当从值为 14 的位置出发时,它会找到一条长度为 9 的路径(如左图所示)。而当从值为13的位置出发时,它会找那条长度为 8 的路径(如右图所示)。
若假设顺序为 14、13、……。则在从 14 出发进行深度优先搜索时,它肯定会先计算从 13 出发得到的最长下降子序列;而从 13 出发时,它又会先计算从12出发得到的最长下降子序列……直到该过程结束,并在最后通过回溯得到从 14 出发得到的最长下降子序列长度。此时,当我们再计算 13 的最长子序列时,它也会重复上述过程,这便是大量重复计算的地方。试想,如果我们在求某个点的最长下降子序列时,对其搜索到的所有点的最长子序列长度进行存储,即:
这样一来,以 14 所在位置为起点涉及到的最长下降序列中的任何点都将在递归过程中找到其自身的最长下降子序列,并且形成记录。这就避免了后续重复寻找 13、12、……、2、1 等值所在位置的最长下降子序列。另一方面,假设现在要求值为 15 的位置处的最长下降子序列,则其只需要做一件事:判断当前这个点是否有更长的下降子序列?如果不是,则当前位置存储的值即为其最大值;否则,就对当前位置继续进行深搜。即,对值为 15 的位置 ( 1 , 1 ) \left(1,\ 1\right) (1, 1) 而言,它只需做一件事:
p a t h ( 1 , 1 ) = max { p a t h ( 1 , 1 ) , D F S ( n e x t P o i n t ) + 1 } path(1,1)=\text{max}\{path(1,1) ,DFS(nextPoint)+1\} path(1,1)=max{path(1,1),DFS(nextPoint)+1}
其中 nextPoint 表示从点 ( 1 , 1 ) \left(1,\ 1\right) (1, 1) 出发能走的下一个点(在给出的例子中, ( 1 , 1 ) \left(1,\ 1\right) (1, 1) 的下一个可行点只有 ( 1 , 2 ) \left(1,\ 2\right) (1, 2),而根据矩阵中存储的值可知,从点 ( 1 , 2 ) \left(1,\ 2\right) (1, 2) 出发能得到的最长下降子序列长度为 9 ),于是有:
p a t h ( 1 , 1 ) = max { p a t h ( 1 , 1 ) , 10 } path(1,1)=\text{max}\{path(1,1) ,10\} path(1,1)=max{path(1,1),10}
显然,对位置 ( 1 , 1 ) \left(1,\ 1\right) (1, 1) 而言,其默认最长下降子序列长度为 p a t h ( 1 , 1 ) = 1 path(1,1)=1 path(1,1)=1(即,仅含自身一个点)。因此,基于以上式子可以直接得到从 ( 1 , 1 ) \left(1,\ 1\right) (1, 1) 出发的最长下降子序列长度为 10。
我们将以上这种记录前面搜索过程相关结果的搜索称为 “记忆化搜索”。在这种需要计算一个矩阵的最长(或最短)路径问题时,记忆化搜索可以大大降低计算成本。
下面直接给出基于以上思路得到的求解本题的完整代码:
/*
MT2239 二维矩阵中的最长下降序列
深度优先搜索、记忆化搜索
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 105;
// 存放矩阵的二维表,对应的访问标记表(记录该位置的最长下降序列长度)
int matrix[N][N], vis[N][N];
// 矩阵规格
int n, m;
// 四种行走方式(上、下、左、右)
int forwardX[] = {0, 0, -1, 1};
int forwardY[] = {-1, 1, 0, 0};
// 录入矩阵信息
void getMatrix()
{
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
cin>>matrix[i][j];
}
// 获取指定位置的最长下降序列长度(带记忆化搜索)
int DFS(int x, int y)
{
// 如果已经被访问过,则直接返回该点记录的最长下降序列长度
if(vis[x][y]) return vis[x][y];
// 否则初始化该点的最长下降序列长度为 1 (即自身)
vis[x][y] = 1;
// 向各方向发散寻找最长下降序列
for(int i=0; i<4; i++){
int nextx = x + forwardX[i];
int nexty = y + forwardY[i];
// 越界或所处位置的数值更大则直接跳过
if(nextx < 1 || nextx > n || nexty < 1 || nexty > m || matrix[nextx][nexty] >= matrix[x][y])
continue;
// 否则将当前的最大下降子序列进行更新
vis[x][y] = max(vis[x][y], DFS(nextx, nexty) + 1);
}
return vis[x][y];
}
// 获取最长下降序列
int getLongestDesSeq()
{
int tmp, longestDesSeq = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++){
tmp = DFS(i, j);
if(tmp > longestDesSeq)
longestDesSeq = tmp;
}
return longestDesSeq;
}
int main( )
{
// 录入数据
cin>>n>>m;
getMatrix();
// 寻找最长下降序列
cout<<getLongestDesSeq()<<endl;
return 0;
}
MT2240 传染病
难度:钻石 时间限制:1秒 占用内存:128M
题目描述
小码哥正在研究传染病的相关知识,现在遇到了这么一个问题:有一个长为 n n n ,宽为 m m m ,高为 k k k (层数)的的长方体,它可以看成 n × m × k n\times m\times k n×m×k 个 1 × 1 × 1 1\times1\times1 1×1×1 大小的单位正方体。每个单位正方体都有一个字符。
.
表示该位置防疫措施不好,如果被传染了就会感染病毒。#
表示该区人民防疫措施良好,永远不会感染病毒(甚至都不会成为病毒的携带者)。现在在长方体的最顶层(层号为 1)某个位置,因实验室泄露爆发了病毒。每过一个单位时间,病毒将扩散至周围 6 个方向的地区。如果某个地区为
#
,那么一定不会被感染并且不会携带病毒同时也不会传播病毒。(但如果这个地方存在泄露的实验室,那么哪怕防疫措施再好也会被感染以及传播病毒)。现在小码哥需要知道,假如第一层坐标为 ( x , y ) \left(x,\ y\right) (x, y) 的实验室泄露了病毒,那么最多会有多少区域被感染。
格式
输入格式:第一行三个正整数 k , n , m ( k , n , m ≤ 10 ) k,\ n,\ m\ (k,\ n,\ m\le10) k, n, m (k, n, m≤10);
接下来 k k k 层,每层 n n n 行,每行 m m m 个字符,表示长方体每个单位的状态;
最后一行两个正整数 x , y ( x ≤ n , y ≤ m ) x,\ y\ \left(x\le n,\ y\le m\right) x, y (x≤n, y≤m) 表示发生泄漏的实验室的坐标(这个实验室在第一层)。输出格式:按题目要求输出一行一个整数表示答案。
样例 1
输入:
3 3 3 .#. ### ##. .## ### ##. ... ... ... 1 1
输出:
13
相关知识点:
广度优先搜索
题解
这道题实际上就是基于广度优先搜索的走格子问题,不同的是这道题里的空间是一个三维空间。为此,我们只需要在BFS中再额外地添加两种行走方式,然后从题目给出的起点进行行走,并逐个统计感染的实验室个数即可。另外,由于广度优先搜索需要用到队列这一数据结构,故为了方便使用我们单独定义了一个类似“三元组”形式的数据结构(结构体),用于表示三维空间中的一个点。
下面直接给出求解本题的完整代码:
/*
MT2240 传染病
广度优先搜索
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 13;
// 存放矩阵的二维表,对应的访问标记表
char cube[N][N][N];
int vis[N][N][N];
// 立方体规格
int k, n, m;
// 六种行走方式(上、下、左、右、前、后)
int forwardX[] = {0, 0, -1, 1, 0, 0};
int forwardY[] = {0, 0, 0, 0, -1, 1};
int forwardZ[] = {-1, 1, 0, 0, 0, 0};
// 封装三维空间中一个点的数据结构
struct Site{
int x, y, z;
Site(){}
Site(int x, int y ,int z):x(x),y(y),z(z){}
};
Site curSite, nextSite;
// 录入立方体信息
void getCube()
{
for(int l=1; l<=k; l++)
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)
cin>>cube[i][j][l];
}
// 检测下个区域是否可达
bool check(Site site){
int x = site.x, y = site.y, z = site.z;
// 测下个区域是否合法
if(x<1 || x>n || y<1 || y>m || z<1 || z>k)
return false;
// 测下个区域能否继续传播病毒
if(vis[x][y][z] || cube[x][y][z] == '#')
return false;
return true;
}
// 计被感染的区块个数(广度优先搜索)
int getInfectedBlocks(int x, int y)
{
int infectedBlocks = 0;
// 初始化队列
queue<Site> q;
q.push(Site(x,y,1));
vis[x][y][1] = true;
// 广度优先搜索
while(!q.empty()){
// 取出当前队头元素
curSite = q.front();
// 队头元素出队列
q.pop();
// 统计被感染数
infectedBlocks++;
// 病毒扩散!
for(int i=0; i<6; i++){
// 扩散后的新位置
nextSite.x = curSite.x + forwardX[i];
nextSite.y = curSite.y + forwardY[i];
nextSite.z = curSite.z + forwardZ[i];
// 若新扩散成立
if(check(nextSite)) {
// 则入队列
q.push(nextSite);
// 置访问标记为真
vis[nextSite.x][nextSite.y][nextSite.z] = true;
}
}
}
return infectedBlocks;
}
int main( )
{
// 录入数据
int x, y;
cin>>k>>n>>m;
getCube();
cin>>x>>y;
// 统计被感染的区块个数
cout<<getInfectedBlocks(x, y)<<endl;
return 0;
}
MT2241 循环空间
难度:钻石 时间限制:1秒 占用内存:256M
题目描述
给出一个二维的由0、1、2组成的 n × n n\times n n×n 空间,0 表示障碍物,1 表示可行走,2 表示起点,这个空间是循环的,如走到左边界再往左走,你会出现在右边界对应位置,我们每次能向上、下、左、右中的一个方向行走一格。
请输出从起点到每个点的最短路径长度。
格式
输入格式:第一行一个正整数 n n n ,表示地图的边长;
接下来 n n n 行,每行 n n n 个整数,0 表示障碍物,1 表示可行走,2 表示起点。
输出格式:输出 n n n 行,每行 n n n 个整数。0 表示起点或无法到达的点,其他数字表示从起点到此处的最短路径长度。样例 1
输入:
5
0 1 2 1 0
0 0 1 0 1
1 1 0 0 1
1 0 0 1 0
1 1 1 0 0输出:
0 1 0 1 0
0 0 1 0 7
5 6 0 0 6
4 0 0 0 0
3 2 1 0 0备注
对于30%的数据: 1 ≤ n ≤ 30 1\le n\le30 1≤n≤30;
对于60%的数据: 1 ≤ n ≤ 300 1\le n\le300 1≤n≤300;
对于100%的数据: 1 ≤ n ≤ 2000 1\le n\le2000 1≤n≤2000。
相关知识点:
广度优先搜索
题解
求二维矩阵中指定点到其余所有点的最短距离,一道典型的广度优先搜索题。不过需要注意的是,本题给出的二维矩阵是 “循环” 的,即处于边界位置并继续往边界方向行走时,会直接走到另一个相对的边界。这相当于是对“行走方式”添加了一种新的准则。我们的处理办法也很简单,将新位置在各维度上的值加上整个二维矩阵的规格(避免了向索引降低的方向行走时出现负的索引),并对该规格取余(避免出现索引出现超过矩阵规格的情况)。
由于本题涉及到的是一个二维空间,因此我们直接利用 STL 提供的模板数据结构 pair
作为 BFS 中队列的基本数据类型。下面直接给出求解本题的完整代码:
/*
MT2241 循环空间
广度优先搜索(必须快读输入数据,否则会超时 3/10 的数据)
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 2005;
// 存放矩阵的二维表,对应的访问标记表(到该点的最短路径)
int matrix[N][N], vis[N][N];
// 矩阵规格,起始点坐标
int n, startX, startY;
// 当前位置和下一个状态所处位置
pair<int, int> curPoint, nextPoint;
// 四种行走方式(上、下、左、右)
int forwardX[] = {0, 0, -1, 1};
int forwardY[] = {-1, 1, 0, 0};
// 录入矩阵信息
void getMatrix()
{
for(int i=0; i<n; i++)
for(int j=0; j<n; j++){
cin>>matrix[i][j];
if(matrix[i][j] == 2){
startX = i;
startY = j;
}
}
}
// 获取从指定位置出发到各点的最短路径长度
void BFS(int x, int y)
{
// 初始化访问标记表
memset(vis, -1, sizeof(vis));
// 初始化队列
queue<pair<int,int> > q;
// 创建当前的点位置
curPoint = make_pair(x,y);
// 入队列
q.push(curPoint);
// 重置访问标记
vis[x][y] = 0;
// 广度优先搜索
while(!q.empty()){
// 取出当前队头元素
curPoint = q.front();
// 队头元素出队列
q.pop();
// 向四个方向行走
for(int i=0; i<4; i++){
// 新位置
nextPoint = make_pair((curPoint.first+forwardX[i]+n) % n,
(curPoint.second+forwardY[i]+n) % n);
// 如果新位置未被访问过且可行走,则更新其值
if(vis[nextPoint.first][nextPoint.second] < 0 && matrix[nextPoint.first][nextPoint.second] == 1){
vis[nextPoint.first][nextPoint.second] = vis[curPoint.first][curPoint.second] + 1;
// 入队列
q.push(nextPoint);
}
}
}
// 整个广度优先搜索结束后,剩余所有尚未被访问的位置将无法到达
for(int i=0; i<n; i++)
for(int j=0; j<n; j++)
if(vis[i][j] < 0)
vis[i][j] = 0;
}
// 输出最短路径长度矩阵
void printPathLength()
{
for(int i=0; i<n; i++){
for(int j=0; j<n; j++)
cout<<vis[i][j]<<" ";
cout<<endl;
}
}
int main( )
{
// 快读输入数据
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
// 录入数据
cin>>n;
getMatrix();
// 寻找从指定点出发的最短路径
BFS(startX, startY);
// 输出指定点到所有点的最短路径长度
printPathLength();
return 0;
}
BD202303 第五维度
难度:星耀 时间限制:1秒 占用内存:64M
题目描述
零维是点,点动成线;
一维是线,线动成面;
二维是面,面动成体;
三维是体,体动成史;
四维是史,史动???
现在人类企图理解第五维度。
小度是第五维度的一位智者。一天,小度发现人类的许多科学家在试图理解第五维度,人类是四维生物,若是他们理解了第五维度,很可能也会到来第五维度的空间,这显然是小度不愿意看到的(毕竟哪里都有人口数量的问题….)所以小度希望他们尽可能晚的理解第五维度,因此,小度用更高维度的视角把所有人类中在理解第五维的科学家都看到了,而这些科学家的智商会不一样,所以他们的理解速度 V i V_i Vi 也会不一样;并且,他们开始理解的时间点 S i S_i Si 也不一样。理解速度 V i V_i Vi 描述为每过单位时间可获得 V i V_i Vi 个单位理解力,也就是说在 S i + 1 S_i+1 Si+1 的时间点该科学家会第一次贡献 V i V_i Vi 的理解力。我们定义理解力总数超过 m m m 时理解了第五维度。 小度因为维度更高,可以使用时间悖论来给人类一次重大的打击,小度可以让任意一位科学家在任意一个时间点消失,所以他接下来的理解不会继续;而且人类不会记得他,所以他之前的贡献会消失。因为小度能力有限,所以小度只能使用一次暂时悖论。现在求在尽可能晚的情况下,人类理解第五维度的最早时间点。时间点初始为 0,但显然,没有科学家能够在 0 时刻有贡献。
格式
输入格式:第一行给出一个整数 n n n 和一个整数 m m m,表示有 n n n 个科学家,在理解力总数超过 m m m 时理解了第五维度;
第二行至第 n + 1 n+1 n+1 行:每行两个整数 S i S_i Si 和 V i V_i Vi 。
对于 100% 的数据: 1 ≤ n ≤ 10 5 , m ≤ 2 × 10 9 , 0 ≤ S i ≤ 2 × 10 9 , 0 ≤ V i ≤ 10 3 1\le n\le{10}^5,m\le2\times{10}^9,0\le S_i\le2\times{10}^9,0\le V_i\le{10}^3 1≤n≤105,m≤2×109,0≤Si≤2×109,0≤Vi≤103。
输出格式:一行,包含一个整数 T T T 表示在尽可能晚的情况下,人类理解第五维度的最早时间点。若人类永远无法理解第五维度,则输出-1
。样例 1
输入:
3 10
0 1
4 6
5 1输出:
8
样例 2
输入:
3 10
0 0
4 0
5 1输出:
-1
备注
对于第一个样例,使得 S i = 4 , V i = 6 {\ S}_i=4,V_i=6 Si=4,Vi=6 的科学家消失,则每个时刻总共理解力为:0 1 2 3 4 5 7 9 11,在时刻 8 超过 m = 10 m=10 m=10,因此输出 8;对于第二个样例,人类永远无法理解第五维度,因此输出
-1
。
相关知识点:
贪心
题解
首先对本题的意思进行一个简化:输入 n n n 个科学家开始理解第五维度的时间点 S i {\ S}_i Si 以及其单位时间能得到的理解力 V i V_i Vi (均为非负整数),那么随着时间的推移,全部科学家的总理解力肯定是不断增加的。一旦总理解力达到了 m m m ,则认为人类能理解第五维度。但是,现在有一个具有上帝视角的人,他总能找到在这些科学家中具有最高理解力的那位并将其从抹除(则他的理解力也将消失),那么这时候人类还能理解第五维度么?如果能,则输出在这样的前提下人类理解第五维度的最早时间;否则输出 -1。
本题中, m m m 的最大取值为 2 × 10 9 2\times{10}^9 2×109 ,那么在极限情况下(只有一个科学家且 S i = 0 , V i = 1 {\ S}_i=0,\ V_i=1 Si=0, Vi=1)的最长时间也是 2 × 10 9 2\times{10}^9 2×109 。可以看出,如果直接枚举时间线算出人类的总理解力,并在抹除具有最高理解力的人后判断与 m m m 的大小关系是极易超时的。在这种情况下,一定要敏锐地想到二分法查找。
对于每一次查找的时间 T T T,可采取下式求解全部人类的总理解力:
for(int i=0; i<n; i++){
if(T > S[i]){
// 累加
sum_comp += ((long long)T - S[i]) * V[i];
}
}
注意,题目要求在尽可能晚的情况下,人类理解第五维度的最早时间点。而尽可能晚,就意味着每次都要抹除此刻对人类理解力共享最大的科学家。为此,我们可以在求全部人类总理解力的同时,记录其中的最大理解力,并在最后减去该值即可,于是有:
// 判断在指定时间下,人类能否理解第五维度
bool check(int T)
{
// 在指定时间下人类的理解力总和、这些理解力中的最大值
long long sum_comp = 0, max_comp = 0, tmp;
// 计算所有人的理解力总和,并找到其中的最大值
for(int i=0; i<n; i++){
if(T > S[i]){
// 计算当前第 i 个人的获取的理解力
tmp = ((long long)T - S[i]) * V[i];
// 累加
sum_comp += tmp;
// 找出具有最大贡献的理解力
max_comp = max(max_comp, tmp);
}
}
// 要求尽可能晚的情况下,那就把具有最大共享的理解力去除即可
return (sum_comp - max_comp > m);
}
下面给出基于以上思路得到的求解本题的完整代码:
/*
BD202303 第五维度
贪心、二分法
*/
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+5;
// 各科学家的理解力起始数组、单位时间增长数组
int S[N], V[N];
// 科学家数量和需要理解五维空间的总理解力
int n, m;
// 判断在指定时间下,人类能否理解第五维度
bool check(int T)
{
// 在指定时间下人类的理解力总和、这些理解力中的最大值
long long sum_comp = 0, max_comp = 0, tmp;
// 计算所有人的理解力总和,并找到其中的最大值
for(int i=0; i<n; i++){
if(T > S[i]){
// 计算当前第 i 个人的获取的理解力
tmp = ((long long)T - S[i]) * V[i];
// 累加
sum_comp += tmp;
// 找出具有最大贡献的理解力
max_comp = max(max_comp, tmp);
}
}
// 要求尽可能晚的情况下,那就把具有最大共享的理解力去除即可
return (sum_comp - max_comp > m);
}
// 二分查找使科学家能理解的最早时间
int BinarySearch()
{
// 能理解的极限情况下,只有 1 个科学家,理解力最小为 1,则最长的时间为 2e9
long long l = 1, r = 2e9;
int ans = -1;
// 二分查找
while(l < r){
int mid = l+r >> 1;
// 判断该时间下(尽可能晚),人类能否理解第五维度
if(check(mid)){
r = mid;
ans = mid;
}else{
l = mid + 1;
}
}
return ans;
}
int main( )
{
// 录入数据
cin>>n>>m;
for(int i=0; i<n; i++)
cin>>S[i]>>V[i];
// 输出使科学家能理解的最早时间
cout<<BinarySearch()<<endl;
return 0;
}