A. Game Shopping
点击查看代码
void solve() {int n, m;std::cin >> n >> m;std::vector<int> a(n), b(m);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}for (int i = 0; i < m; ++ i) {std::cin >> b[i];}int ans = 0;for (int i = 0, j = 0; i < n && j < m; ++ i) {if (b[j] >= a[i]) {++ ans;++ j;}}std::cout << ans << "\n";
}
B. Minimum Ternary String
题意:给你一个只包含\(0, 1, 2\)的数组,你可以交换相邻的\(1,0\)或者\(1, 2\),求可以得到的最小字典序。
我们可以把所有1都移动到一个2的前面,为了字典序最小,应该把这些1都移动第一个2前面。
点击查看代码
void solve() {std::string s;std::cin >> s;int n = s.size();std::string a, b;for (int i = 0; i < n; ++ i) {if (s[i] != '1') {a += s[i];} else {b += s[i];}}if (b.empty() || a.empty()) {std::cout << s << "\n";} else {for (int i = 0; i < a.size(); ++ i) {if (a[i] == '2') {a = a.substr(0, i) + b + a.substr(i);std::cout << a << "\n";return;}}std::cout << a + b << "\n";}
}
C. Annoying Present
题意:给你\(m\)个\(x_i, d_i\),每次你选择一个位置\(p\),使得\(sum += \sum_{j=1}^{n} x_i + d_i \times |p - j|\)。求\(sum\)最大。
显然\(x_i\)与操作位置无关,直接加上\(n\)个。对于\(d_i\),如果它大于等于\(0\),我们希望它乘的数的和最大,如果小于\(0\),希望它乘的数的和最小,那么我们可以预处理找出可以得到的\(\sum_{j=1}^{n} |p - j|\)最大的位置和最小的位置。
点击查看代码
void solve() {int n, m;std::cin >> n >> m;std::vector<i64> x(m), d(m);i64 sum = 0;for (int i = 1; i <= n; ++ i) {sum += i - 1;}i64 max = sum, min = sum;for (int i = 2; i <= n; ++ i) {sum += i - 1 - (n - i + 1);max = std::max(max, sum);min = std::min(min, sum);}i64 ans = 0;for (int i = 0; i < m; ++ i) {std::cin >> x[i] >> d[i];ans += x[i] * n;if (d[i] >= 0) {ans += d[i] * max;} else {ans += d[i] * min;}}std::cout << std::fixed << std::setprecision(12);std::cout << (double)ans / n << "\n";
}
D. Relatively Prime Graph
题意:给你\(n\)个点,你要构造\(m\)条边,使得每条边\((u, v)\)都有\(gcd(u, v) = 1\),且图联通。
首先想要图联通,\(m\)至少是\(n-1\)。
然后我们可以发现,\(1\)可以产生\(n-1\)条边,\(2\)可以产生\(n - \lfloor \frac{n}{2} \rfloor\)条边,于是我们可以猜测如果暴力找的话很快就能找到。
点击查看代码
void solve() {int n, m;std::cin >> n >> m;if (m < n - 1) {std::cout << "Impossible\n";return;}std::vector<std::pair<int, int>> ans;for (int i = 1; i <= n && ans.size() < m; ++ i) {for (int j = i + 1; j <= n && ans.size() < m; ++ j) {if (std::gcd(i, j) == 1) {ans.emplace_back(i, j);}}}if (ans.size() < m) {std::cout << "Impossible\n";} else {std::cout << "Possible\n";for (auto & [u, v] : ans) {std::cout << u << " " << v << "\n";}}
}
E. Intercity Travelling
题意:你要从\(1\)到\(n\),每次移动花费\(a_s\)的代价,其中\(s\)是连续的不休息次数加一,每个点有\(\frac{1}{2}\)的概率让你休息,你在\(1\)号点已经休息过了。需要求出到达\(n\)的代价的期望乘上\(2^{n-1}\)。
由于\(1\)是固定休息的,那么其它点关于休不休息有\(2^{n-1}\)可能,也就是期望的分母是\(2^{n-1}\),那么答案要求乘上这个相当于把它消去了。
那么我们可以每个\(a_i\)会贡献多少次,这个需要讨论一下,因为如果\(a_i\)在\(pos\)得到,那么\([pos - i, pos - 1]\)都不能休息,其它\(n - i - 1\)个位置随便选,但\(1\)号点固定的,如果\(pos = i\),那么有\(n - i\)个位置随便选。那么就是两种情况加起来。
答案为\(\sum_{i=1}^{n} (2^{n-i} + (n - i) \times 2^{n-i-1}) \times a_i\)。
代码省略取模类
点击查看代码
void solve() {int n;std::cin >> n;std::vector<int> a(n + 1);for (int i = 1; i <= n; ++ i) {std::cin >> a[i];}Z ans = 0;for (int i = 1; i <= n; ++ i) {ans += (power<Z>(2, n - i) + (n - i) * power<Z>(2, n - i - 1)) * a[i];}std::cout << ans << "\n";
}