BD202311 夏日漫步
夏日夜晚,小度看着庭院中长长的走廊,萌发出想要在上面散步的欲望,小度注意到月光透过树荫落在地砖上,并且由于树荫的遮蔽度不通,所以月光的亮度不同,为了直观地看到每个格子的亮度,小度用了一些自然数来表示它们的亮度。亮度越高则数字越大,亮度相同的数字相同。
走廊是只有一行地砖的直走廊。上面一共有 nn 个格子,每个格子都被小度给予了一个数字 a_iai 来表示它的亮度。
小度现在站在 11 号格子,想要去到 nn 号格子。小度可以正向或反向移动到相邻的格子,每次需要花费 11 的体力。
同时小度还有瞬移的能力,其可以花费 11 的体力来瞬移到与当前格子亮度相同的格子上。而且由于小度视野有限,只能瞬移到在当前格子后的第一次亮度相同的格子上。这也意味着不能反向瞬移。
小度想知道,到达 nn 号格子需要花费的最小体力是多少。以此制定一个最优秀的散步方案。
格式
输入格式:
第一行一个整数 nn ,表示走廊上一共有 nn 个格子。 1\leq n \leq 2*10^51≤n≤2∗105 , 0\leq a_i \leq 1*10^60≤ai≤1∗106; 第二行 nn 个整数,为自然数 a_iai 表示第 ii 号格子的亮度。
输出格式:
一行,一个整数costcost表示花费的最小体力。
样例 1
输入:
6
0 1 2 3 1 5
复制
输出:
3
复制
1.
思路是搞一个dis数组,大小是n,一一对应每一个位置,从0号位置到达每一个位置的最近的距离,消耗最少的体力值是多少,只需要用BFS维护好这个dis值即可.
2.
BFS层次遍历,每一次走一步,有三种情况,要么是往前走一步,要么是往后走一步,要么是瞬移,这些消耗的体力值都是1.
3.
利用nextt数组存储每一个位置瞬移的下一个位置的下标,如果不存在可以瞬移的位置就填-1.
4.
如何维护next数组,有两种办法,第一种办法利用map存储值和下标的映射,值与下标的映射始终保证是最后一次出现的下标值.
遍历arr数组,对于i位置的元素值,看一下map里面有没有这个值,如果有,维护这个map中的nextt值.如果没有什么都不做,然后将i位置添加到map中.
5.
第二种维护nextt的办法就是排序,node结构体绑定元素值和下标,然后按照元素值排序,元素值相等按照下标排序.
map维护nextt
#include<bits/stdc++.h> // 包含所有标准库
using namespace std;
#define int long long // 定义int为long long,便于处理大数
#define endl '\n' // 将换行符定义为'\n'
int n; // 定义格子数
vector<int> arr; // 定义亮度数组
vector<int> next_; // 定义下一个相同亮度格子的位置数组
map<int, int> prev_; // 定义一个映射,用于存储上一次出现相同亮度的格子的位置
int ret = 0; // 定义返回值
vector<int> dis; // 定义距离数组
void bfs() { // 广度优先搜索函数
queue<int> q; // 定义队列用于BFS
dis[1] = 0; // 初始化起点的距离为0
q.push(1); // 将起点入队
while (!q.empty()) { // 当队列不为空时
int top = q.front(); // 获取队首元素
q.pop(); // 弹出队首元素
if (top == 0) continue; // 如果当前格子为0,跳过(不可能发生,因为起点为1)
if (dis[top + 1] == -1) { // 如果可以向右移动且未访问
dis[top + 1] = dis[top] + 1; // 更新右侧格子的距离
q.push(top + 1); // 将右侧格子入队
if (top + 1 == n) return; // 如果到达终点,结束函数
}
if (top - 1 >= 0 && dis[top - 1] == -1) { // 如果可以向左移动且未访问
dis[top - 1] = dis[top] + 1; // 更新左侧格子的距离
q.push(top - 1); // 将左侧格子入队
}
if (next_[top] != -1 && dis[next_[top]] == -1) { // 如果可以瞬移且未访问
dis[next_[top]] = dis[top] + 1; // 更新瞬移目标格子的距离
q.push(next_[top]); // 将瞬移目标格子入队
if (next_[top] == n) return; // 如果到达终点,结束函数
}
}
}
void solve() { // 解决问题的函数
dis.assign(n + 1, -1); // 初始化距离数组,所有元素设为-1
ret = 0; // 重置返回值
next_.assign(n + 1, -1); // 初始化下一个相同亮度格子的位置数组
prev_.clear(); // 清空映射
for (int i = 1; i <= n; i++) { // 遍历每个格子
if (prev_.count(arr[i])) { // 如果当前亮度值之前出现过
next_[prev_[arr[i]]] = i; // 更新上一次出现相同亮度格子的位置的下一个相同亮度格子的位置
}
prev_[arr[i]] = i; // 更新当前亮度值出现的位置
}
bfs(); // 执行广度优先搜索
cout << dis[n] << endl; // 输出到达终点的最小体力
}
signed main() { // 主函数
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); // 快速输入输出
cin >> n; // 输入格子数
arr.assign(n + 1, -1); // 初始化亮度数组
for (int i = 1; i <= n; i++) { // 输入每个格子的亮度
cin >> arr[i];
}
solve(); // 调用solve函数解决问题
return 0; // 返回0
}
排序维护nextt
#include<bits/stdc++.h> // 包含所有标准库
using namespace std;
#define DEBUG // 定义DEBUG标志
#ifdef DEBUG
#define BUG(code) do{code}while(0); // 如果定义了DEBUG,则执行code块
#else
#define BUG(code) do{}while(0); // 如果没有定义DEBUG,则不执行code块
#endif
#define int long long // 将int定义为long long,便于处理大数
#define endl '\n' // 将换行符定义为'\n'
#define FAST() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); // 快速输入输出宏
#define p pair<int, int> // 定义p为pair<int, int>类型
#define ff first // 定义ff为first
#define ss second // 定义ss为second
#define pb push_back // 定义pb为push_back
#define ppb pop_back() // 定义ppb为pop_back()
#define ltu(i, a, b) for(int i = a; i <= b; i++) // 定义ltu为从a到b的for循环
#define utl(i, a, b) for(int i = a; i >= b; i--) // 定义utl为从a到b的倒序for循环
#define tests() int t; cin >> t; while(t--) // 定义tests为测试用例循环
int n; // 定义变量n
vector<int> arr; // 定义亮度数组
vector<int> dis; // 定义距离数组
vector<int> nextt; // 定义下一个相同亮度格子的位置数组
struct node { // 定义结构体node
int val; // 亮度值
int index; // 下标
};
vector<node> arr1; // 定义node结构体的数组
void bfs() { // 广度优先搜索函数
queue<int> q; // 定义队列用于BFS
dis[0] = 0; // 初始化起点的距离为0
q.push(0); // 将起点入队
while (!q.empty()) { // 当队列不为空时
auto top = q.front(); // 获取队首元素
q.pop(); // 弹出队首元素
if (top == n - 1) { // 如果到达终点
cout << dis[top] << endl; // 输出到达终点的最小体力
return; // 结束函数
}
if (top - 1 >= 0 && dis[top - 1] == -1) { // 如果可以向左移动且未访问
dis[top - 1] = dis[top] + 1; // 更新左侧格子的距离
q.push(top - 1); // 将左侧格子入队
}
if (top + 1 < n && dis[top + 1] == -1) { // 如果可以向右移动且未访问
dis[top + 1] = dis[top] + 1; // 更新右侧格子的距离
q.push(top + 1); // 将右侧格子入队
}
if (nextt[top] != -1 && dis[nextt[top]] == -1) { // 如果可以瞬移且未访问
dis[nextt[top]] = dis[top] + 1; // 更新瞬移目标格子的距离
q.push(nextt[top]); // 将瞬移目标格子入队
}
}
}
void solve() { // 解决问题的函数
dis.assign(n, -1); // 初始化距离数组,所有元素设为-1
nextt.assign(n, -1); // 初始化下一个相同亮度格子的位置数组
sort(arr1.begin(), arr1.end(), [](const node &a, const node &b) { // 对arr1按亮度和下标排序
if (a.val == b.val) {
return a.index < b.index; // 如果亮度相同,按下标排序
} else {
return a.val < b.val; // 否则按亮度排序
}
});
ltu(i, 0, n - 2) { // 遍历arr1
if (arr1[i].val == arr1[i + 1].val) { // 如果相邻两个格子的亮度相同
nextt[arr1[i].index] = arr1[i + 1].index; // 更新nextt数组
}
}
bfs(); // 执行广度优先搜索
// BUG(
// ltu(i, 0, n - 1) {
// cout << dis[i] << " ";
// }
// cout << endl;
// );
}
signed main() { // 主函数
FAST(); // 快速输入输出
cin >> n; // 输入格子数
arr.assign(n, 0); // 初始化亮度数组
arr1.assign(n, node()); // 初始化node结构体数组
ltu(i, 0, n - 1) { // 输入每个格子的亮度
cin >> arr[i];
arr1[i].val = arr[i]; // 将亮度赋值给arr1
arr1[i].index = i; // 记录下标
}
solve(); // 调用solve函数解决问题
return 0; // 返回0
}
BD202314 跑步
小度每天早上要和小猫一起跑步。小猫的位置数值越小表示越在后面,速度越小表示越慢,它们都向一个方向跑。
小猫比较喜欢一起跑,所以当速度更快的小猫遇见速度慢的小猫时,它就会放慢速度,变成一组一起跑。注意,初始位置相同的小猫直接组成一组。
请问最终不再有追赶上的情况时,最多一组有多少只小猫?
格式
输入格式:
第一行输入的是整数 nn,1 \le n \le 10^51≤n≤105; 接下来的nn行分别包含小猫的初始位置 pp 和速度 vv ,1 \le p,v \le 10^8 1≤p,v≤108。
输出格式:
一行,一个数字,表示最多有多少小猫在一组。
样例 1
输入:
5
6 1
1 1
3 2
1 2
2 3
复制
输出:
3
复制
备注
样例解释:位置速度为(3,2),(2,3)的小猫会追上(6,1)的小猫,而位置速度为(1,2)的小猫则会和(1,1)一起,所以最多三只小猫一组。
1.
对于一个小猫,如果他的速度不会变小,可以一直跑下去,说明它前面的小猫的速度全部都大于它.
对于一个小猫,如果他的速度会变小,说明前面有速度小于它的小猫.
小猫的相对位置不会改变,i位置的小猫速度是v,那么i后面的小猫要么和小猫一起,要么在i位置小猫后面.
i前面的小猫要么和小猫一起,要么在i位置前面.
2.
按照位置大小进行排序,从小到大,如果位置相等按照速度进行排序,从小到大.
3.
从后往前遍历,最后一个小猫可以一直跑下去,他会带多少个小猫一起跑?速度大于他的小猫都会带上.速度小于等于他的小猫,一定追不上.
4.
记录每一个组的小猫数量的最大值.
#include<bits/stdc++.h> // 包含所有标准库
using namespace std;
#define int long long // 定义int为long long,便于处理大数
#define endl '\n' // 将换行符定义为'\n'
int n; // 定义小猫数量
struct node { // 定义结构体node
int p, v; // p表示位置,v表示速度
};
vector<node> arr; // 定义node结构体的数组
int ret = 0; // 定义返回值
void solve() { // 解决问题的函数
sort(arr.begin(), arr.end(), [](const node& a, const node& b) { // 对arr排序
if (a.p != b.p) return a.p < b.p; // 按位置升序排序
else return a.v > b.v; // 如果位置相同,按速度降序排序
});
int count = 0; // 计数当前组的小猫数量
int minv = LLONG_MAX; // 定义当前组的小猫最小速度
for (int i = arr.size() - 1; i >= 0; i--) { // 从后往前遍历
if (arr[i].v <= minv) { // 如果当前小猫的速度小于等于当前组的最小速度
minv = arr[i].v; // 更新最小速度
count = 0; // 重置计数
}
count++; // 计数加一
ret = max(ret, count); // 更新最大组的小猫数量
}
cout << ret << endl; // 输出结果
}
signed main() { // 主函数
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); // 快速输入输出
cin >> n; // 输入小猫数量
arr.assign(n, node()); // 初始化node结构体数组
for (int i = 0; i < n; i++) { // 输入每只小猫的位置和速度
cin >> arr[i].p >> arr[i].v;
}
solve(); // 调用solve函数解决问题
return 0; // 返回0
}
BD202321 新材料
小度最近在研究超导材料,他合成了 NN 个新材料排成一排,而每个材料根据基于流程会设置一个编号 PP,表示种类。 小度发现相同种类的材料在距离小于等于 KK 的情况下会发生发应。 小度想知道哪些种类的材料会发生反应,输出这些种类 PP 的异或值。
格式
输入格式:
第一行,两个整数 N, KN,K(1 \le K \le N \le 500001≤K≤N≤50000); 接下来 NN 行,每行一个整数,即该位置材料的的种类编号 PP( 0 \le P \le 10000000≤P≤1000000)。
输出格式:
一行,一个整数,会发生反应的种类 PP 的异或值。
样例 1
输入:
5 3
1
2
4
1
4
复制
输出:
5
复制
备注
材料1,4会发生反应,异或值为5。
1.
同样是维护nextt数组,可以用map维护也可以用排序维护.
map维护nextt
#include<bits/stdc++.h> // 包含所有标准库
using namespace std;
// #define PrDEBUG // 定义调试宏
#ifdef PrDEBUG
#define de(x) cerr<<"Line "<<__LINE__<<": "<<#x<<" = "<<x<<endl // 如果定义了PrDEBUG,则输出调试信息
#else
#define de(x) // 如果没有定义PrDEBUG,则不输出调试信息
#endif
#define int long long // 定义int为long long,便于处理大数
#define endl '\n' // 将换行符定义为'\n'
#define FAST() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0) // 快速输入输出宏
#define p pair<int, int> // 定义p为pair<int, int>类型
#define ff first // 定义ff为first
#define ss second // 定义ss为second
#define pb push_back // 定义pb为push_back
#define ppb pop_back // 定义ppb为pop_back
#define ltu(i, a, b) for(int i = a; i <= b; ++i) // 定义ltu为从a到b的for循环
#define utl(i, a, b) for(int i = a; i >= b; --i) // 定义utl为从a到b的倒序for循环
#define tests() int t; cin >> t; while(t--) // 定义tests为测试用例循环
int N, K; // 定义材料数量N和最大距离K
vector<int> arr; // 定义材料种类编号数组
vector<int> nextt; // 定义下一个相同种类材料的距离数组
map<int, int> prevv; // 定义一个映射,用于存储上一次出现相同种类材料的位置
int ret = 0; // 定义返回值
void solve() { // 解决问题的函数
ret = 0; // 初始化返回值
nextt.assign(1000001, LLONG_MAX); // 初始化nextt数组,大小为1000001,所有元素设为LLONG_MAX
prevv.clear(); // 清空映射
de(arr[5]); // 调试信息
ltu(i, 1, N) { // 遍历每个材料
if(prevv.count(arr[i])) { // 如果当前材料的种类之前出现过
de(i); // 调试信息
nextt[arr[i]] = min(nextt[arr[i]], i - prevv[arr[i]]); // 更新该种类材料的最小距离
}
prevv[arr[i]] = i; // 更新当前种类材料的位置
}
ltu(i, 1, 1000000) { // 遍历所有可能的种类
if(nextt[i] <= K) ret ^= i; // 如果该种类材料的最小距离小于等于K,则更新返回值
}
cout << ret << endl; // 输出结果
}
signed main() { // 主函数
FAST(); // 快速输入输出
cin >> N >> K; // 输入材料数量和最大距离
arr.assign(N + 1, 0); // 初始化材料种类编号数组
ltu(i, 1, N) { // 输入每个材料的种类编号
cin >> arr[i];
}
solve(); // 调用solve函数解决问题
return 0; // 返回0
}
排序维护nextt
#include<bits/stdc++.h> // 包含所有标准库
using namespace std;
#define PrDEBUG // 定义调试宏
#ifdef PrDEBUG
#define de(x) cerr<<"Line "<<__LINE__<<": "<<#x<<" = "<<(x)<<endl // 如果定义了PrDEBUG,则输出调试信息
#else
#define de(x) // 如果没有定义PrDEBUG,则不输出调试信息
#endif
#define int long long // 定义int为long long,便于处理大数
#define endl '\n' // 将换行符定义为'\n'
#define FAST() ios::sync_with_stdio(0), cin.tie(0), cout.tie(0) // 快速输入输出宏
#define p pair<int, int> // 定义p为pair<int, int>类型
#define ff first // 定义ff为first
#define ss second // 定义ss为second
#define pb push_back // 定义pb为push_back
#define ppb pop_back // 定义ppb为pop_back
#define ltu(i, a, b) for(int i = a; i <= b; ++i) // 定义ltu为从a到b的for循环
#define utl(i, a, b) for(int i = a; i >= b; --i) // 定义utl为从a到b的倒序for循环
#define tests() int t; cin >> t; while(t--) // 定义tests为测试用例循环
int N, K; // 定义材料数量N和最大距离K
struct node { // 定义结构体node
int bianhao; // 材料编号
int indexx; // 材料位置索引
};
vector<node> arr; // 定义node结构体的数组
map<int, bool> mapp; // 定义一个映射,用于存储已经处理过的材料种类
int ret = 0; // 定义返回值
void solve() { // 解决问题的函数
ret = 0; // 初始化返回值
mapp.clear(); // 清空映射
// 对arr进行排序,首先按编号升序排序,如果编号相同按索引升序排序
sort(arr.begin(), arr.end(), [](const node& a, const node& b) {
if (a.bianhao == b.bianhao) {
return a.indexx < b.indexx;
} else {
return a.bianhao < b.bianhao;
}
});
// 遍历所有材料,检查相邻的同种材料是否在最大距离K内
ltu(i, 1, N - 1) {
if (arr[i].bianhao == arr[i + 1].bianhao && !mapp.count(arr[i].bianhao)) { // 如果相邻材料编号相同且该编号未处理过
if (arr[i+1].indexx - arr[i].indexx <= K) { // 检查相邻材料是否在最大距离K内
mapp[arr[i].bianhao] = true; // 标记该编号已经处理过
ret ^= arr[i].bianhao; // 将该编号的值加入结果异或值
}
}
}
cout << ret << endl; // 输出结果
}
signed main() { // 主函数
FAST(); // 快速输入输出
cin >> N >> K; // 输入材料数量和最大距离
arr.assign(N + 1, node()); // 初始化node结构体数组
ltu(i, 1, N) { // 输入每个材料的编号
cin >> arr[i].bianhao;
arr[i].indexx = i; // 记录材料的位置索引
}
solve(); // 调用solve函数解决问题
return 0; // 返回0
}
结尾
最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。
同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。
谢谢您的支持,期待与您在下一篇文章中再次相遇!