AtCoder Beginner Contest 292
A - CAPS LOCK (abc292 a)
题目大意
给定一个小写字母串,将其转换成大写字母。
解题思路
调库,或者按照ascii码转换即可。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); string s; cin >> s; for(auto &i : s) i = toupper(i); cout << s << endl; return 0; }
B - Yellow and Red Card (abc292 b)
题目大意
个人, 个事件,分三种:给某人黄牌,给某人红牌,问某人是否被罚下场。
如果一人被罚两张黄牌或一张红牌则被罚下场。
回答每个询问。
解题思路
按照题意,维护每个人的黄牌和红牌数量模拟即可。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, q; cin >> n >> q; vector<vector<int>> cnt(2, vector<int>(n, 0)); while(q--){ int c, x; cin >> c >> x; c --; x --; if (c == 2){ if (cnt[0][x] < 2 && cnt[1][x] < 1) cout << "No" << '\n'; else cout << "Yes" << '\n'; }else cnt[c][x] ++; } return 0; }
C - Four Variables (abc292 c)
题目大意
给定,问有多少正整数组,满足
解题思路
给定,预处理 的方案数。
然后枚举的乘积 ,则 的乘积为 ,其两个方案数相乘。然后累加即是答案。
时间复杂度为
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n; cin >> n; vector<int> cnt(n + 1); for(int i = 1; i <= n; ++ i) for(int j = 1; j <= n; ++ j){ if (1ll * i * j > n) break; cnt[i * j] ++; } LL ans = 0; for(int i = 1; i < n; ++ i) ans += 1ll * cnt[i] * cnt[n - i]; cout << ans << '\n'; return 0; }
D - Unicyclic Components (abc292 d)
题目大意
给定一张无向图,问每个连通块是否满足:其边数
与点数
相等。
解题思路
用并查集
维护连通性,同时维护连通块的边数
和点数
,最后一一判断即可。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; class dsu { public: vector<int> p; vector<int> psz; vector<int> esz; int n; dsu(int _n) : n(_n) { p.resize(n); psz.resize(n); esz.resize(n); iota(p.begin(), p.end(), 0); fill(psz.begin(), psz.end(), 1); fill(esz.begin(), esz.end(), 0); } inline int get(int x) { return (x == p[x] ? x : (p[x] = get(p[x]))); } inline bool unite(int x, int y) { x = get(x); y = get(y); esz[y] ++; if (x != y) { p[x] = y; psz[y] += psz[x]; esz[y] += esz[x]; return true; } return false; } inline bool check(){ for(int i = 0; i < p.size(); ++ i){ if (get(i) == i && psz[i] != esz[i]){ return false; } } return true; } }; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, m; cin >> n >> m; dsu d(n); for(int i = 0; i < m; ++ i){ int u, v; cin >> u >> v; -- u, -- v; d.unite(u, v); } if (d.check()) cout << "Yes" << '\n'; else cout << "No" << '\n'; return 0; }
E - Transitivity (abc292 e)
题目大意
给定一张有向图。如果对于三个点, , ,则必须有边 。
问最少添加多少条边,使得对于任意三个点,都满足以上性质。
解题思路
考虑一条链,从左连到右,容易发现左边的点与右边的每个点都要连一条边。
即从一个点出发,它能到达的所有点,在最终的图都要与其连边。
因此从每个点,求得其能到达的所有点数。对所有点累加即是最终图的边数,减去已有的边数,则是需要添加的最小边数。
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, m; cin >> n >> m; vector<vector<int>> edge(n); for(int i = 0; i < m; ++ i){ int u, v; cin >> u >> v; -- u, -- v; edge[u].push_back(v); } int ans = 0; auto bfs = [&](int st){ queue<int> team; team.push(st); int cnt = 0; vector<int> visit(n, 0); visit[st] = 1; while(!team.empty()){ auto u = team.front(); team.pop(); for(auto &v : edge[u]){ if (!visit[v]){ ++ cnt; team.push(v); visit[v] = 1; } } } return cnt; }; for(int i = 0; i < n; ++ i) ans += bfs(i); ans -= m; cout << ans << '\n'; return 0; }
F - Regular Triangle Inside a Rectangle (abc292 f)
题目大意
给定一个矩阵,问其内接的最大正三角形的边长是多少。
解题思路
从样例的图我们可以进行猜测:
- 三角形的一个顶点在矩形的顶点上
- 当矩形的长不够长时,三角形的另外两个点都在矩形的边上。
设的角为 ,矩形长,宽 (),三角形边长 ,根据正三角形边相等和高中数学知识可得
用和角公式将拆开,然后解方程得到
因为这里,所以 应该大于 。因此这里就有个边界条件
一旦不满足,说明长 太大了,此时三角形最大的情况,就是其高和矩形的宽相等,即三角形的边长就是
否则,算得,
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int a, b; cin >> a >> b; if (a < b) swap(a, b); long double sq3 = sqrt(3); if (2.0 * b / a < sq3){ double x = b / sq3 * 2; cout << fixed << setprecision(15) << x << '\n'; }else { long double tan = 2.0 * b / a - sq3; long double cos = sqrt(1 / (1 + tan * tan)); long double x = a / cos; cout << fixed << setprecision(15) << x << '\n'; } return 0; }
G - Count Strictly Increasing Sequences (abc292 g)
题目大意
给定个长度为 的包含数字和 ?
的字符串。
将这些 ?
替换数字。问有多少种替换方案,满足
解题思路
应该是个数位DP竟然是区间。
首先数的大小可以转换成字典序大小的比较。
状态切分点
来源于字典序大小的定义
的递归性: ,当且仅当 ,或者 且 ,而 可以看成原问题(或者可以看成 )的一个子问题。
因此,我们考虑要确保,那首先会有前个串,其第一个数字是相同的,假设为,即
此时问题就转换成:前个串的后 个数字的满足题目条件的方案数,与,后面串的 个数字的满足题目条件,且第一个数字要大于的方案数,的乘积。
即设表示区间 的字符串,考虑的位置, 且第个数字是大于等于 的,满足题目条件的方案数。
那么原问题是 ,当前个串的第一个数字都是 时(这意味着后面串的第一个数字要大于),原问题就切分成两部分的乘积:
根据字典序大小的递归定义,第一项就是 且 的情况,第二项就是的情况,都是满足的条件。
由此枚举转移即可,写成 就不用脑子了,注意下边界条件。
状态复杂度是,转移是 ,总复杂度是
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; const int mo = 998244353; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, m; cin >> n >> m; vector<string> s(n); for(auto &i : s) cin >> i; vector<vector<vector<vector<int>>>> dp(n, vector<vector<vector<int>>>(n, vector<vector<int>>(m, vector<int>(10, -1)))); function<int(int, int, int, int)> dfs = [&](int l, int r, int k, int f){ if (k == m) return int(l == r); if (l > r) return 1; if (f >= 10) return 0; if (dp[l][r][k][f] != -1) return dp[l][r][k][f]; int val = dfs(l, r, k, f + 1); for(int i = l; i <= r; ++ i){ if (s[i][k] != '?' && s[i][k] != '0' + f) break; val = val + 1ll * dfs(l, i, k + 1, 0) * dfs(i + 1, r, k, f + 1) % mo; val %= mo; } return dp[l][r][k][f] = val; }; int ans = dfs(0, n - 1, 0, 0); cout << ans << '\n'; return 0; }
Ex - Rating Estimator (abc292 h)
题目大意
给定场比赛的表现分,经过第 场比赛后,将变成 。但当超过 后便不再涨了。
处理一下 次操作,输出每次操作完后,经过这 场比赛最后的 值。
每次操作给定 ,将第 场比赛的 表现分 更改为 。
操作是持久化的。
解题思路
先考虑不修改的,这里用到一个转换技巧跟abc236 E一样。
我们要找,即,即
即对于新数组,原问题找最小的 使得满足上述条件,就转换成找最小的使得 满足前缀和大于 。
维护前缀和的最大值,然后二分查找。
考虑修改的话,用线段树维护这个前缀和的最大值,然后在线段树上二分就可以了。复杂度不变,都是
神奇的代码
#include <bits/stdc++.h> using namespace std; using LL = long long; class segtree { #define lson (root << 1) #define rson (root << 1 | 1) int n; vector<LL> sum; vector<LL> max; void build(int root, int l, int r, const vector<LL> &v) { if (l == r) { sum[root] = v[l - 1]; max[root] = v[l - 1]; return; } int mid = (l + r) >> 1; build(lson, l, mid, v); build(rson, mid + 1, r, v); sum[root] = sum[lson] + sum[rson]; max[root] = std::max(max[lson], sum[lson] + max[rson]); } void update(int root, int l, int r, int pos, LL val){ if (l == r){ sum[root] = val; max[root] = val; return; } int mid = (l + r) >> 1; if (pos <= mid) update(lson, l, mid, pos, val); else update(rson, mid + 1, r, pos, val); sum[root] = sum[lson] + sum[rson]; max[root] = std::max(max[lson], sum[lson] + max[rson]); } pair<int, LL> query(int root, int l, int r, LL presum){ if (l == r) return {l, presum + max[root]}; int mid = (l + r) >> 1; if (presum + max[lson] >= 0) return query(lson, l, mid, presum); else return query(rson, mid + 1, r, presum + sum[lson]); } public: void build(const vector<LL> &v){ n = v.size(); sum.resize(4 * (n + 1), 0); max.resize(4 * (n + 1), 0); build(1, 1, n, v); } void update(int pos, LL val){ assert(1 <= pos && pos <= n); update(1, 1, n, pos, val); } pair<int, LL> query(){ return query(1, 1, n, 0); } }; int main(void) { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); int n, q; LL b; cin >> n >> b >> q; vector<LL> a(n); for(auto &i : a){ cin >> i; i -= b; } segtree seg; seg.build(a); while(q--){ int c; LL x; cin >> c >> x; seg.update(c, x - b); auto [pos, sum] = seg.query(); double ans = b + 1.0 * sum / pos; cout << fixed << setprecision(15) << ans << '\n'; } return 0; }
本文作者:~Lanly~
本文链接:https://www.cnblogs.com/Lanly/p/17179400.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步