AtCoder Beginner Contest 407
A - Approximation
点击查看代码
void solve() {
int a, b;
std::cin >> a >> b;
int res = a / b;
if (a % b > b - a % b) {
++ res;
}
std::cout << res << "\n";
}
B - P(X or Y)
题意:两次筛子求和大于等于\(x\)差大于等于\(y\)的概率。
暴力枚举
点击查看代码
void solve() {
int x, y;
std::cin >> x >> y;
int sum = 6 * 6, ans = 0;
for (int i = 1; i <= 6; ++ i) {
for (int j = 1; j <= 6; ++ j) {
if (i + j >= x || std::abs(i - j) >= y) {
++ ans;
}
}
}
std::cout << std::fixed << std::setprecision(12);
std::cout << (double)ans / sum << "\n";
}
C - Security 2
题意:从空串变成\(s\),每次从后面加入一个\(0\),或者让所有数加一模\(10\)。求最少操作数。
实际是模拟,对于一个递减的子串,可以花费最大值加子串长度的操作使得这一段满足。但这样会改变前面的值,那么假设需要操作\(k\)次,那么前面的先操作\((10 - k) \% 10\)次,这样操作完后前面的也是正确的。
点击查看代码
void solve() {
std::string s;
std::cin >> s;
int n = s.size();
int ans = 0;
for (int i = 0; i < n; ++ i) {
int j = i;
while (j + 1 < n && s[j + 1] <= s[j]) {
++ j;
}
ans += s[i] - '0';
if (i != 0) {
ans += (10 - (s[i] - '0')) % 10;
}
i = j;
}
std::cout << ans + n << "\n";
}
D - Domino Covering XOR
题意:在一个矩阵上放\(1\times2, 2\times 1\)的牌,求没被覆盖的位置的异或和的最大值。
可以把所有可能的覆盖方案枚举出来,然后爆搜,每个方案对应两个点,如果两个点都没被覆盖才能用这个方案,因为大部分方案都和其它有重复的,所以爆搜过程中实际用到的不多。
点击查看代码
void solve() {
int n, m;
std::cin >> n >> m;
std::vector<i64> a(n * m);
std::vector<std::pair<int, int>> b;
i64 sum = 0;
for (int i = 0; i < n; ++ i) {
for (int j = 0; j < m; ++ j) {
i64 x;
std::cin >> x;
sum ^= x;
a[i * m + j] = x;
if (j + 1 < m) {
b.emplace_back(i * m + j, i * m + j + 1);
}
if (i + 1 < n) {
b.emplace_back(i * m + j, (i + 1) * m + j);
}
}
}
i64 ans = 0;
std::vector<int> st(n * m);
auto dfs = [&](auto & self, int u, i64 sum) -> void {
if (u == b.size()) {
ans = std::max(ans, sum);
return;
}
auto & [x, y] = b[u];
if (st[x] || st[y]) {
self(self, u + 1, sum);
return;
}
self(self, u + 1, sum);
st[x] = st[y] = 1;
self(self, u + 1, sum ^ a[x] ^ a[y]);
st[x] = st[y] = 0;
};
dfs(dfs, 0, sum);
std::cout << ans << "\n";
}
E - Most Valuable Parentheses
题意:一个\(2\times n\)的数组\(a\),你要构造一个合法的括号序列,然后可以得到每个\(s_i=\)'('的\(a_i\)的值。求和最大。
考虑从左到右加入右括号,保证每个前缀右括号的数量小于等于左括号数量,那么如果把\(i\)加入右括号后不满足条件,则需要弹出右括号,因为每个前缀都是合法的,那么不管弹出哪个右括号也不会影响合法性,那么应该从大到小弹,用大根堆模拟就行。
点击查看代码
void solve() {
int n;
std::cin >> n;
std::vector<int> a(2 * n);
for (int i = 0; i < 2 * n; ++ i) {
std::cin >> a[i];
}
std::priority_queue<i64> heap;
i64 sum = 0;
for (int i = 0; i < 2 * n; ++ i) {
heap.push(a[i]);
sum += a[i];
while (heap.size() > (i + 1) / 2) {
sum -= heap.top();
heap.pop();
}
}
i64 ans = std::accumulate(a.begin(), a.end(), 0ll) - sum;
std::cout << ans << "\n";
}
int main() {
std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
//scanf("%d", &T);
while (T -- ) {
solve();
}
return 0;
}
F - Sums of Sliding Window Maximum
题意:给你一个数组,对于每一个\(k \in [1, n]\),求数组所有长度为\(k\)的子数组的最大值的和。
这种题还是见少了,以前做过这种单调栈的题,但忘了枚举短区间是\(nlogn\)的性质。
用单调栈求出每个位置作为最大值的区间[l_i, r_i],那么可以枚举左端点\(j\),那么\([i - j + 1, r_j - j + 1]\)的答案都要加\(a_i\)。也可以枚举右端点\([j - i + 1, j - l_i + 1]\)的答案都加\(a_i\)。选择枚举短的区间,这个区间长度小于等于\(\frac{r_i - l_1 + 1}{2}\)。均摊下来是\(nlogn\)的。
点击查看代码
#define ls (u << 1)
#define rs (u << 1 | 1)
#define umid (tr[u].l + tr[u].r >> 1)
template <class Info, class Tag>
struct Node {
int l, r;
Info info;
Tag tag;
};
template <class Info, class Tag>
struct LazySegmentTree {
std::vector<Node<Info, Tag> > tr;
LazySegmentTree(int _n) {
init(_n);
}
LazySegmentTree(std::vector<Info> & a) {
int _n = (int)a.size();
init(_n, a);
}
void init(int _n) {
tr.assign(_n << 2, {});
build(0, _n - 1);
}
void init(int _n, std::vector<Info> & a) {
tr.assign(_n << 2, {});
build(0, _n - 1, a);
}
void pushup(int u) {
tr[u].info = tr[ls].info + tr[rs].info;
}
void pushdown(Node<Info, Tag> & u, Tag tag) {
u.info = u.info + tag;
u.tag = u.tag + tag;
}
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 l, int r, int u = 1) {
tr[u] = {l, r, {}};
if (l == r) {
return;
}
int mid = l + r >> 1;
build(l, mid, ls); build(mid + 1, r, rs);
pushup(u);
}
void build(int l, int r, std::vector<Info> & a, int u = 1) {
tr[u] = {l, r, {}};
if (l == r) {
tr[u].info = a[l];
return;
}
int mid = l + r >> 1;
build(l, mid, a, ls); build(mid + 1, r, a, rs);
pushup(u);
}
void modify(int l, int r, Tag tag, int u = 1) {
if (l <= tr[u].l && tr[u].r <= r) {
pushdown(tr[u], tag);
return;
}
pushdown(u);
int mid = umid;
if (l <= mid) {
modify(l, r, tag, ls);
}
if (r > mid) {
modify(l, r, tag, rs);
}
pushup(u);
}
Info query(int l, int r, int u = 1) {
if (l <= tr[u].l && tr[u].r <= r) {
return tr[u].info;
}
pushdown(u);
int mid = umid;
if (r <= mid) {
return query(l, r, ls);
} else if (l > mid) {
return query(l, r, rs);
}
return query(l, r, ls) + query(l, r, rs);
}
// int query_first_not_appear(int u = 1) {
// if (tr[u].l == tr[u].r) {
// return tr[u].l;
// }
// pushdown(u);
// int mid = umid;
// if (tr[ls].info.sum != tr[ls].info.len) {
// return query_first_not_appear(ls);
// } else {
// return query_first_not_appear(rs);
// }
// }
};
struct Info {
i64 sum, len = 1;
};
struct Tag {
i64 add;
bool exist() {
return add != 0;
}
void clear() {
add = 0;
}
};
Info operator + (const Info & a, const Info & b) {
Info res{};
res.sum = a.sum + b.sum;
res.len = a.len + b.len;
return res;
}
Info operator + (const Info & a, const Tag & b) {
Info res{};
res.sum = a.sum + a.len * b.add;
res.len = a.len;
return res;
}
Tag operator + (const Tag & a, const Tag & b) {
Tag res{};
res.add = a.add + b.add;
return res;
}
void solve() {
int n;
std::cin >> n;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
a.push_back(1e9);
std::vector<int> l(n + 1), r(n + 1);
std::stack<std::pair<int, int>> stk;
stk.emplace(1e9 + 1, -1);
for (int i = 0; i <= n; ++ i) {
while (a[i] >= stk.top().first) {
r[stk.top().second] = i - 1;
stk.pop();
}
l[i] = stk.top().second + 1;
stk.emplace(a[i], i);
}
LazySegmentTree<Info, Tag> tr(n + 1);
for (int i = 0; i < n; ++ i) {
if (i - l[i] <= r[i] - i) {
for (int j = l[i]; j <= i; ++ j) {
int x = i - j + 1, y = r[i] - j + 1;
tr.modify(x, y, Tag{a[i]});
}
} else {
for (int j = r[i]; j >= i; -- j) {
int x = j - i + 1, y = j - l[i] + 1;
tr.modify(x, y, Tag{a[i]});
}
}
}
for (int i = 1; i <= n; ++ i) {
std::cout << tr.query(i, i).sum << "\n";
}
}

浙公网安备 33010602011771号