A 既不是最小值也不是最大值
排序后取中间
class Solution {
public:
int findNonMinOrMax(vector<int>& nums) {
if (nums.size() < 3)
return -1;
sort(nums.begin(), nums.end());
return nums[1];
}
};
B 执行子串操作后的字典序最小字符串
模拟: 找到第一个不是’a’的位置, 以其为操作区间的左端点, 操作区间的右端点为从左端点开始连续的最后一个不为’z’的位置, 若串中字符全为’a’,则只操作最后一个位置.
class Solution {
public:
string smallestString(string s) {
int n = s.size();
int i = 0;
for (; i < n; i++)
if (s[i] != 'a')
break;
if (i == n) {
s[n - 1] = 'z';
return s;
}
for (; i < n && s[i] != 'a'; i++)
s[i] -= 1;
return s;
}
};
C 收集巧克力
枚举: 显然最优方案的操作次数最多为 n − 1 n-1 n−1, 所以可以枚举方案的操作次数, 当操作次数为 o p op op时, 最初坐标 i i i可以选择 [ i , i + o p − 1 ] [i,i+op-1] [i,i+op−1] (若 i + o p − 1 ≥ n − 1 i+op-1 \ge n-1 i+op−1≥n−1则为 [ i , n − 1 ] ∪ [ 0 , o p + i − n ] [i,n-1] \cup [0,op+i-n] [i,n−1]∪[0,op+i−n])区间内的任意值, 可以提前预处理求出所有区间的最小值
class Solution {
public:
typedef long long ll;
long long minCost(vector<int>& a, int x) {
int n = a.size();
int mn[n][n];//区间最小值
for (int i = 0; i < n; i++)
mn[i][i] = a[i];
for (int len = 2; len <= n; len++)
for (int i = 0; i + len - 1 < n; i++)
mn[i][i + len - 1] = min(mn[i][i + len - 2], a[i + len - 1]);
ll res = INT64_MAX;
for (int op = 0; op < n; op++) {
ll cur = 1LL * op * x;
for (int i = 0; i < n; i++) {
ll t = i + op < n ? mn[i][i + op] : min(mn[i][n - 1], mn[0][op + i - n]);
cur += t;
}
res = min(res, cur);
}
return res;
}
};
D 最大和查询
区间最值: 1) 设两个数组为 a a a和 b b b, 若存在 i i i, j j j使得 a i < a j a_i<a_j ai<aj且 b i < b j b_i<b_j bi<bj, 则 ( a i , b i ) (a_i, b_i) (ai,bi)的和不会是任意查询的答案, 所以可以从数组中删除 ( a i , b i ) (a_i, b_i) (ai,bi). 要删掉所以这样的数可以先将数对数组 { ( a k , b k ) } \{(a_k,b_k)\} {(ak,bk)}非降序排序, 再用单调栈的方法将数对数组的 b k b_k bk序列调整成非升序. 2)之后针对每一个查询 < x , y > <x,y> <x,y>, 用二分的方法, 只考虑 x x x将得到数对数组上满足条件的下标区间 [ r i g h t , n − 1 ] [right,n-1] [right,n−1], 类似只考虑 y y y将得到数对数组上满足条件的下标区间 [ 0 , l e f t ] [0,left] [0,left], 同时考虑 x x x和 y y y满足的区间即为 [ l e f t , r i g h t ] [left,right] [left,right](若两区间交集为空返回-1), 通过线段树求区间最大值.
typedef long long ll;
const int maxn = 1e5 + 5;
struct SegmentTree {
ll tl;
ll tr;
ll s;
ll mark;
int lazy;
};
SegmentTree st[maxn * 4];
inline void push_down(ll index) {
st[index << 1].lazy = 1;
st[index << 1 | 1].lazy = 1;
st[index << 1].mark += st[index].mark;
st[index << 1 | 1].mark += st[index].mark;
st[index << 1].s += st[index].mark;
st[index << 1 | 1].s += st[index].mark;
st[index].lazy = 0;
st[index].mark = 0;
}
inline void push_up(ll index) {
st[index].s = max(st[index << 1].s, st[index << 1 | 1].s);
}
void build(ll l, ll r, vector<pair<int, int>> &li0, ll index = 1) {
st[index].tl = l;
st[index].tr = r;
st[index].lazy = 0;
st[index].mark = 0;
if (l == r) {
st[index].s = li0[l - 1].first + li0[l - 1].second;
} else {
ll mid = (l + r) >> 1;
build(l, mid, li0, index << 1);
build(mid + 1, r, li0, index << 1 | 1);
push_up(index);
}
}
ll query(ll l, ll r, ll index = 1) {
if (l <= st[index].tl and st[index].tr <= r) {
return st[index].s;
} else {
if (st[index].lazy)
push_down(index);
if (r <= st[index << 1].tr)
return query(l, r, index << 1);
else if (l > st[index << 1].tr)
return query(l, r, index << 1 | 1);
return max(query(l, r, index << 1), query(l, r, index << 1 | 1));
}
}
class Solution {
public:
vector<int> maximumSumQueries(vector<int> &a1, vector<int> &a2, vector<vector<int>> &queries) {
int n = a1.size();
vector <pair<int, int>> li, st;
for (int i = 0; i < n; i++)
li.emplace_back(a1[i], a2[i]);
sort(li.begin(), li.end());
for (auto x: li) {//st模拟栈, 最终{st[i].first}非降序, {st[i].second}非升序
while (!st.empty() && st.back().second < x.second)
st.pop_back();
st.push_back(x);
}
n = st.size();//更新n
build(1, n, st);//建树
vector<int> res;
for (auto &qi: queries) {
int left, right;
int l = 0, r = n, mid;
while (l < r) {
mid = (l + r) / 2;
if (st[mid].first >= qi[0])
r = mid;
else
l = mid + 1;
}
left = l;//满足qi[0]的区间为[left,n-1]
l = -1, r = n - 1;
while (l < r) {
mid = (l + r + 1) / 2;
if (st[mid].second >= qi[1])
l = mid;
else
r = mid - 1;
}
right = l;//满足qi[1]的区间为[left,n-1]
if (left <= right)
res.push_back(query(left + 1, right + 1));
else
res.push_back(-1);
}
return res;
}
};