A.Fast Food Restaurant
题意:一共有3种物品,每种物品每次只能取一个或零个,问一共能组成多少种组合
题解:取一个、两个、三个,一共就7种情况讨论一下即可
#include <bits/stdc++.h> using namespace std; const int maxn = 2e5 + 10; const int INF = 0x3f3f3f3f; typedef pair<int, int> pii; void solve() { int a[3]; for (int i = 0; i < 3; i++) scanf("%d", &a[i]); sort(a, a + 3, greater<int>()); int ans = 0; if (a[0]) a[0]--, ans++; if (a[1]) a[1]--, ans++; if (a[2]) a[2]--, ans++; if (a[0] && a[1]) a[0]--, a[1]--, ans++; if (a[0] && a[2]) a[0]--, a[2]--, ans++; if (a[1] && a[2]) a[1]--, a[2]--, ans++; if (a[0] && a[1] && a[2]) a[0]--, a[1]--, a[2]--, ans++; printf("%d\n", ans); } int main() { int t; for (scanf("%d", &t); t >= 1; t--) solve(); return 0; }
B.Different Rules
题意:一个人参加两场比赛,一共n个人,第一次第x名,第二次y名,询问他两场的名次相加最高能取得第几名以及最低能取得第几名
题解:对于最低的名次,只要将第一次的第1名与第二次的第x+y-1名、第一次的第2名与第二次的第x+y-2名...这样就能构造出x+y-1个x+y分的人,他的最低名次就是x+y-1。对于最高名次,如果x+y<=n,那么就可以通过第一次的第1名与第二次的第n名、第一次的第2名与第二次的第n-1名...将剩下的构造成n+1分,使他成为第1名;如果x+y>n,那么将两次比赛的第一名组合一起、第二名组合一起...设组合了t组,使得x-t+y-t<=n-t,就满足了新的x+y<=n,可以算出t=x+y-n,所以他最高就是第x+y-n+1名
#include <bits/stdc++.h> using namespace std; typedef pair<int, int> pii; typedef long long ll; const int maxn = 2e5 + 10; const int INF = 0x3f3f3f3f; int n, x, y; int get_min() { if (x + y <= n) return 1; return min(n, x + y - n + 1); } int get_max() { return min(n, x + y - 1); } void solve() { scanf("%d%d%d", &n, &x, &y); if (x > y) swap(x, y); printf("%d %d\n", get_min(), get_max()); } int main() { int t; for (scanf("%d", &t); t >= 1; t--) solve(); return 0; }
C.Skyscrapers(单调栈/分治+线段树)
题意:要建建筑,要求对于任意一个不能同时存在左、右都有比它高的建筑,同时对于每个i都有给定的mi,每个i不能超过mi。询问这些建筑高度和最大能是多少。
题解:显然满足题意的一定是一个单峰序列,于是可以考虑第i个当最高点的时候,左边的最大总和,而这个是可以递推的,因为当mi>=mi-1的时候第i个可以直接取mi加上去,而当mi<mi-1的时候,要把之前所有大于mi的都变成mi,而之前的部分是单增的,于是可以开个单调栈来维护,复杂度O(n),同理右边的最大总和也可以这么算。还有一种方法:找出区间里的最小值mi,分治,比较左边都取mi+solve右边与左边solve+右边都取mi的大小。用线段树来维护区间。
单调栈:
#include <bits/stdc++.h> using namespace std; const int maxn = 5e5 + 10; const int INF = 0x3f3f3f3f; typedef pair<int, int> pii; typedef long long ll; ll a[maxn], pre[maxn], nex[maxn], l[maxn], r[maxn]; int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lld", &a[i]); a[0] = a[n + 1] = 0ll; stack<int> s; s.push(0); for (int i = 1; i <= n; i++) { while (a[s.top()] >= a[i]) s.pop(); pre[i] = s.top(); s.push(i); l[i] = l[pre[i]] + a[i] * (i - pre[i]); } while (!s.empty()) s.pop(); s.push(n + 1); for (int i = n; i >= 1; i--) { while (a[s.top()] >= a[i]) s.pop(); nex[i] = s.top(); s.push(i); r[i] = r[nex[i]] + a[i] * (nex[i] - i); } ll mx = 0; int id = 0; for (int i = 1; i <= n; i++) if (mx < l[i] + r[i] - a[i]) mx = l[i] + r[i] - a[i], id = i; for (int i = id - 1; i >= 1; i--) a[i] = min(a[i], a[i + 1]); for (int i = id + 1; i <= n; i++) a[i] = min(a[i], a[i - 1]); for (int i = 1; i <= n; i++) printf("%lld ", a[i]); puts(""); return 0; }
分治+线段树
#include <bits/stdc++.h> using namespace std; const int maxn = 5e5 + 7; int n; long long a[maxn], b[maxn]; typedef pair<long long, int> SgTreeDataType; struct treenode { int L, R; SgTreeDataType mi, lazy; } tree[maxn * 4]; inline void push_up(int o) { if (tree[2 * o].mi.first == 0) tree[2 * o].mi = {1e9 + 7, 1e9}; if (tree[2 * o + 1].mi.first == 0) tree[2 * o + 1].mi = {1e9 + 7, 1e9}; if (tree[2 * o].mi.first > tree[2 * o + 1].mi.first) tree[o].mi = tree[2 * o + 1].mi; else tree[o].mi = tree[2 * o].mi; } inline void build_tree(int L, int R, int o) { tree[o].L = L, tree[o].R = R; if (L == R) tree[o].mi = {a[L], L}; if (R > L) { int mid = (L + R) >> 1; build_tree(L, mid, o * 2); build_tree(mid + 1, R, o * 2 + 1); push_up(o); } } inline SgTreeDataType query(int QL, int QR, int o) { int L = tree[o].L, R = tree[o].R; if (QL <= L && R <= QR) return tree[o].mi; else { int mid = (L + R) >> 1; SgTreeDataType mi = {1e9 + 7, 1}; if (QL <= mid) { SgTreeDataType res = query(QL, QR, 2 * o); if (res.first < mi.first) mi = res; } if (QR > mid) { SgTreeDataType res = query(QL, QR, 2 * o + 1); if (res.first < mi.first) mi = res; } push_up(o); return mi; } } long long solve(int l, int r) { if (l > r) return 0L; if (l == r) { b[l] = a[l]; return 1ll * a[l]; } pair<long long, int> mi = query(l, r, 1); long long sum1 = solve(l, mi.second - 1); long long sum2 = solve(mi.second + 1, r); if (1ll * ((r - mi.second - 1) + 1) * mi.first + mi.first + sum1 > 1ll * ((mi.second - 1 - l) + 1) * mi.first + mi.first + sum2) { for (int i = mi.second; i <= r; i++) b[i] = mi.first; return 1ll * ((r - mi.second - 1) + 1) * mi.first + mi.first + sum1; } else { for (int i = l; i <= mi.second; i++) b[i] = mi.first; return 1ll * ((mi.second - 1 - l) + 1) * mi.first + mi.first + sum2; } } int main() { scanf("%d", &n); for (int i = 1; i <= n; i++) scanf("%lld", &a[i]); build_tree(1, n, 1); solve(1, n); for (int i = 1; i <= n; i++) cout << b[i] << " "; cout << endl; }