A. Comparing Two Long Integers
题意:给你两个可能包含前导零的数字,判断它们的大小关系。
去除前导零后,先判断位数,位数相同再判断大小。
点击查看代码
void solve() {std::string a, b;std::cin >> a >> b;std::reverse(a.begin(), a.end());std::reverse(b.begin(), b.end());while (a.size() > 1 && a.back() == '0') {a.pop_back();}while (b.size() > 1 && b.back() == '0') {b.pop_back();}std::reverse(a.begin(), a.end());std::reverse(b.begin(), b.end());if (a.size() == b.size()) {if (a > b) {std::cout << ">\n";} else if (a < b) {std::cout << "<\n";} else {std::cout << "=\n";}} else if (a.size() > b.size()) {std::cout << ">\n";} else {std::cout << "<\n";}
}
B. Dinner with Emma
题意:给你一个矩阵,第一个人选择行,第二个人选择列,结果就是改行列格子上的数。第一个希望结果更大,第二个希望结果更小。求结果。
因为第二个人肯定选一行中最小的那一个,所以第一个人应该选择最小数最大的一行。
点击查看代码
void solve() {int n, m;std::cin >> n >> m;std::vector a(n, std::vector<int>(m));int max = 0;for (int i = 0; i < n; ++ i) {for (int j = 0; j < m; ++ j) {std::cin >> a[i][j];}max = std::max(max, *std::min_element(a[i].begin(), a[i].end()));}std::cout << max << "\n";
}
C. The Labyrinth
题意:给你一个字符矩阵,有些地方是障碍,有些地方是空地,判断每个障碍变成空地后所在的空地联通块有多少空地。
用并查集维护空地联通块及其个数,然后对于每个障碍将相邻的空地联通块加到set里去重记录答案即可。
点击查看代码
struct DSU {std::vector<int> fa, cnt;DSU(int _n) {init(_n);}void init(int _n) {fa.assign(_n, 0);cnt.assign(_n, 1);std::iota(fa.begin(), fa.end(), 0);}int find(int x) {return x == fa[x] ? x : fa[x] = find(fa[x]);}bool merge(int x, int y) {x = find(x), y = find(y);if (x == y) {return false;}fa[y] = x;cnt[x] += cnt[y];return true;}bool same(int x, int y) {return find(x) == find(y);}int size(int x) {return cnt[find(x)];}
};void solve() {int n, m;std::cin >> n >> m;std::vector<std::string> s(n);for (int i = 0; i < n; ++ i) {std::cin >> s[i];}auto get = [&](int i, int j) -> int {return i * m + j;};const int dx[] = {-1, 0, 1, 0}, dy[] = {0, 1, 0, -1};DSU dsu(n * m);for (int i = 0; i < n; ++ i) {for (int j = 0; j < m; ++ j) {if (s[i][j] == '.') {for (int k = 0; k < 4; ++ k) {int x = i + dx[k], y = j + dy[k];if (x < 0 || x >= n || y < 0 || y >= m || s[x][y] == '*') {continue;}dsu.merge(get(i, j), get(x, y));}}}}std::vector<std::string> ans(n, std::string(m, '.'));for (int i = 0; i < n; ++ i) {for (int j = 0; j < m; ++ j) {if (s[i][j] == '*') {std::set<int> set;for (int k = 0; k < 4; ++ k) {int x = i + dx[k], y = j + dy[k];if (x < 0 || x >= n || y < 0 || y >= m || s[x][y] == '*') {continue;}set.insert(dsu.find(get(x, y)));}int sum = 1;for (auto & id : set) {sum += dsu.size(id);}ans[i][j] = '0' + sum % 10;}}}for (int i = 0; i < n; ++ i) {std::cout << ans[i] << "\n";}
}
D. Longest k-Good Segment
题意:给你一个数字,判断最长的子序列其中不同元素不超过\(k\)个。
双指针经典题,维护每个数出现次数双指针扫描记答案。
点击查看代码
void solve() {int n, k;std::cin >> n >> k;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}const int N = 1e6 + 5;std::vector<int> cnt(N);int ans = 0, ansl = 0, ansr = 0, sum = 0;for (int i = 0, j = 0; j < n;) {while (j < n && sum + (cnt[a[j]] == 0) <= k) {if ( ++ cnt[a[j]] == 1) {++ sum;}++ j;}if (j - i > ans) {ans = j - i;ansl = i;ansr = j - 1;}if ( -- cnt[a[i]] == 0) {-- sum;}++ i;}std::cout << ansl + 1 << " " << ansr + 1 << "\n";
}
E. Sum of Remainders
题意:给你两个数\(n, m\),求\(\sum_{i=1}^{m} n \% i\)的值。
也是经典题,今年牛客寒假集训营考过。
考虑数论分块,对于每个\([l, r]\),有任意的\(i \in [l, r], j \in [l, r]\)且\(\frac{n}{l} = \frac{n}{r}\),则\(n\)对它们取模的模数形成一个等差序列,首项为\(n \% l\),公差为\(\frac{n}{l}\)。
点击查看代码
void solve() {i64 n, m;std::cin >> n >> m;Z ans = (Z)std::max(0ll, m - n) * n;m = std::min(m, n);for (i64 l = 1; l <= m;) {i64 r = std::min(m, n / (n / l));Z a = n % l, d = n / l;ans += (Z)(r - l + 1) * (a + a - d * (Z)(r - l)) / 2;l = r + 1;}std::cout << ans << "\n";
}
F. Expensive Strings
待补