小蓝正在数轴上挖矿,数轴上一共有 n 个矿洞,第 ii 个矿洞的坐标为 ai 。 小蓝从 0 出发,每次可以向左或向右移动 1 的距离,当路过一个矿洞时,就会进行挖矿作业,获得 1 单位矿石,但一个矿洞不能被多次挖掘。小蓝想知道在移动距离不超过 m 的前提下,最多能获得多少单位矿石?
输入格式
输入的第一行包含两个正整数 n,m,用一个空格分隔。
第二行包含 n 个整数 -a1,a2,⋯,an,相邻整数之间使用一个空格分隔。
输出格式
输出一行包含一个整数表示答案。
样例输入
5 4
0 -3 -1 1 2
样例输出
4
解题思路
- 矿洞的坐标有正有负但是数组的下标没有负数,我们可以创建两个数组,分别存储正负的。
- 用前缀和减少计算量,注意前缀和数组要多开一个空间0。通过暴力枚举所有可能找最大值
cpp
for(int i = 1;i <= m;i++){
int sum = r[i];//向右走i
if(m - 2*i > 0) sum += l[m-2*i];//剩下m-2*i向左走,因为要返回
ans = max(ans,sum);//更新答案
sum = l[i];
if(m - 2*i > 0) sum += r[m-2*i];
ans = max(ans,sum);//更新答案
}
3.在起点位置的矿单独计数,否则来回会加两次
cpp
if(!pos) f++;
cout << ans+f << endl;//f是0处的矿数量,单独列出,如果存到前缀和数组中会加两次
完整代码
cpp
#include <bits/stdc++.h>
using namespace std;
const int INF = 2e6+10;
vector<int> r(INF,0);
vector<int> l(INF,0);
int main(){
int n,m;
cin >> n >> m;
int ans = 0;
int f = 0;
for(int i = 0;i < n;i++){
int pos = 0;
cin >> pos;
if(pos > 0) r[pos] += 1;
else l[abs(pos)] += 1;
if(!pos) f++;
}
l[0] = r[0] = 0;
for(int i = 1;i <= m;i++){
l[i] += l[i-1];
r[i] += r[i-1];
}
for(int i = 1;i <= m;i++){
int sum = r[i];//向右走i
if(m - 2*i > 0) sum += l[m-2*i];//剩下m-2*i向左走,因为要返回
ans = max(ans,sum);//更新答案
sum = l[i];
if(m - 2*i > 0) sum += r[m-2*i];
ans = max(ans,sum);//更新答案
}
cout << ans+f << endl;//f是0处的矿数量,单独列出,如果存到前缀和数组中会加两次
return 0;
}