A. Preparing for the Olympiad
题意,有两个数组a和b,如果你选了a数组中第i个,那么对手获得b数组第i+1个,求你们得分的差值最大。
直接加上所有ai > bi+1的就行。
点击查看代码
void solve() {int n;std::cin >> n;std::vector<int> a(n), b(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}for (int i = 0; i < n; ++ i) {std::cin >> b[i];}int ans = a[n - 1];for (int i = 0; i + 1 < n; ++ i) {ans += std::max(0, a[i] - b[i + 1]);}std::cout << ans << "\n";
}
B. Journey
题意:你要走n米,每天走的米数是一个长度为三的循环a, b, c。求需要多少天走完n米。
按三天一起走看能走几次,剩下的米数直接模拟即可。
点击查看代码
void solve() {i64 n, a, b, c;std::cin >> n >> a >> b >> c;i64 ans = n / (a + b + c) * 3;n %= a + b + c;if (n > 0) {++ ans;n -= a;}if (n > 0) {++ ans;n -= b;}if (n > 0) {++ ans;}std::cout << ans << "\n";
}
C. Preparing for the Exam
题意:有n个题目,你知道k个题的答案,然后有m个试卷,你只有全部答对才算行,每个试卷只有一个题没有在里面。
很明显,k至少要为n - 1,否则完不成任何一个答卷,直接看答卷少的那个题是不是我也没有就行。
如果k等于n,都是1。
点击查看代码
void solve() {int n, m, k;std::cin >> n >> m >> k;std::vector<int> st(n), a(m);for (int i = 0; i < m; ++ i) {std::cin >> a[i];-- a[i];}for (int i = 0; i < k; ++ i) {int x;std::cin >> x;st[x - 1] = 1;}std::string ans;for (int i = 0; i < m; ++ i) {if (k < n - 1) {ans += '0';} else if (k == n - 1) {if (st[a[i]] == 0) {ans += '1';} else {ans += '0';}} else {ans += '1';}}std::cout << ans << "\n";
}
D. Counting Pairs
题意:有n个数,你要减去一对数,使得减去后x <= sum <= y。
对于每个数,它可以选的数是有一个范围的,如果sum - ai >= y, 那么最少减sum - ai - y, 最多减sum - ai - x, 如果sum - ai >= x, 那么最少减0, 最多减sum - ai - x, 否则没有满足的范围。
我是直接离散化后求区间和,因为只能和后面的匹配,所以从后往前做,用树状数组维护。(这样好像很麻烦)
点击查看代码
template <typename T>
struct Fenwick {int n;std::vector<T> a;Fenwick(int n_ = 0) {init(n_);}void init(int n_) {n = n_;a.assign(n + 1, T{});}void add(int x, const T &v) {for (int i = x; i <= n; i += i & -i) {a[i] = a[i] + v;}}T sum(int x) {T ans{};for (int i = x; i ; i -= i & -i) {ans = ans + a[i];}return ans;}T rangeSum(int l, int r) {return sum(r) - sum(l);}
};void solve() {i64 n, x, y;std::cin >> n >> x >> y;std::vector<i64> a(n), b;for (int i = 0; i < n; ++ i) {std::cin >> a[i];b.push_back(a[i]);}i64 sum = std::accumulate(a.begin(), a.end(), 0ll);std::vector<std::pair<i64, i64> > Q(n);for (int i = n - 1; i >= 0; -- i) {if (sum - a[i] >= y) {Q[i].first = sum - a[i] - y;Q[i].second = sum - a[i] - x;b.push_back(Q[i].first);b.push_back(Q[i].second);} else if (sum - a[i] >= x) {Q[i].first = 0;Q[i].second = sum - a[i] - x;b.push_back(Q[i].first);b.push_back(Q[i].second);} else {Q[i] = {-1e18, -1e18};}}std::sort(b.begin(), b.end());b.erase(std::unique(b.begin(), b.end()), b.end());int m = b.size();Fenwick<i64> tr(m);i64 ans = 0;for (int i = n - 1; i >= 0; -- i) {auto & [l, r] = Q[i];if (l == -1e18 || r == -1e18) {continue;}l = std::lower_bound(b.begin(), b.end(), l) - b.begin() + 1;r = std::lower_bound(b.begin(), b.end(), r) - b.begin() + 1;ans += tr.rangeSum(l - 1, r); a[i] = std::lower_bound(b.begin(), b.end(), a[i]) - b.begin() + 1;tr.add(a[i], 1);}std::cout << ans << "\n";
}
E. Best Price
题意:n个客人来买东西,对于每个顾客,如果你的商品价格小于等于ai,那么他会直接买,如果大于ai小于等于bi,他会给一个差评但还是会买,否则他就什么都不干。
这题用了线段树,感觉DE这两题都是写的一坨,正解很短,排序然后一个循环就过去了。
首先我们的价格一定是某个a或者某个b,然后维护每个数是否满足条件,然后会买的的人有多少个就行。
点击查看代码
#define ls (u << 1)
#define rs (u << 1 | 1)struct Info {i64 sum, len;
};struct Tag {i64 add;bool exist() {return add != 0;}void clear() {add = 0;}
};struct Node {int l, r;Info info;Tag tag;
};int n, m, P;Info operator + (Info a, Info b) {return {a.sum + b.sum, a.len + b.len};
}Info operator + (Info a, Tag b) {a.sum += b.add * a.len;return a;
}Tag operator + (Tag a, Tag b) {a.add += b.add;return a;
}struct SegmentTree {std::vector<Node> tr;SegmentTree(int n) {tr.assign(n << 2, {});build(1, 1, n);};void pushup(int u) {tr[u].info = tr[ls].info + tr[rs].info;}void pushdown(Node & u, Tag t) {u.info = u.info + t;u.tag = u.tag + t;}void pushdown(int u) {if (tr[u].tag.exist()) {pushdown(tr[ls], tr[u].tag);pushdown(tr[rs], tr[u].tag);tr[u].tag.clear();}}void build(int u, int l, int r) {tr[u] = {l, r};if (l == r) {tr[u].info.len = 1;return;}int mid = l + r >> 1;build(ls, l, mid); build(rs, mid + 1, r);pushup(u);}void modify(int u, int l, int r, Tag t) {if (l <= tr[u].l && tr[u].r <= r) {pushdown(tr[u], t);return;}pushdown(u);int mid = tr[u].l + tr[u].r >> 1;if (l <= mid) {modify(ls, l, r, t);}if (r > mid) {modify(rs, l, r, t);}pushup(u);}Info query(int u, int l, int r) {if (l <= tr[u].l && tr[u].r <= r) {return tr[u].info;}pushdown(u);int mid = tr[u].l + tr[u].r >> 1;if (r <= mid) {return query(ls, l, r);} else if (l > mid) {return query(rs, l, r);}return query(ls, l, r) + query(rs, l, r);}
};void solve() {int n, k;std::cin >> n >> k;std::vector<i64> a(n), b(n);std::vector<i64> nums;for (int i = 0; i < n; ++ i) {std::cin >> a[i];nums.push_back(a[i]);}for (int i = 0; i < n; ++ i) {std::cin >> b[i];nums.push_back(b[i]);}nums.push_back(-1e18);nums.push_back(1e18);std::sort(nums.begin(), nums.end());nums.erase(std::unique(nums.begin(), nums.end()), nums.end());int m = nums.size();auto get = [&](i64 x) -> int {return std::lower_bound(nums.begin(), nums.end(), x) - nums.begin() + 1;};SegmentTree tr1(m), tr2(m);for (int i = 0; i < n; ++ i) {tr1.modify(1, get(a[i]) + 1, get(b[i]), {1});}for (int i = 0; i < n; ++ i) {tr2.modify(1, get(b[i]), get(b[i]), {1});}i64 ans = 0;for (int i = 0; i < n; ++ i) {if (tr1.query(1, get(a[i]), get(a[i])).sum <= k) {ans = std::max(ans, a[i] * (n - tr2.query(1, 1, get(a[i]) - 1).sum));}if (tr1.query(1, get(b[i]), get(b[i])).sum <= k) {ans = std::max(ans, b[i] * (n - tr2.query(1, 1, get(b[i]) - 1).sum));}}std::cout << ans << "\n";
}
F. Joker
赛时想到思路但没写完。。。
待补
G. Snakes
待补