比賽連結:https://codeforces.com/contest/1546
A. AquaMoon and Two Arrays
題意
給出兩個大小為 \(n\) 的陣列 \(a, b\) ,每次可以選擇 \(a\) 中的兩個元素分別加一減一,計算將 \(a\) 變為 \(b\) 的操作次數和步驟。
題解
資料範圍較小,直接模擬即可。
若資料範圍較大,可用棧或佇列分別儲存 \(a_i \lt b_i\) 和 \(a_i \gt b_i\) 的數,這樣每次查詢的時間複雜度就降到了 \(O_{(1)}\) 。
程式碼
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> a(n), b(n);
int suma = 0, sumb = 0;
for (int i = 0; i < n; i++) {
cin >> a[i];
suma += a[i];
}
for (int i = 0; i < n; i++) {
cin >> b[i];
sumb += b[i];
}
if (suma != sumb) {
cout << -1 << "\n";
continue;
}
vector<pair<int, int>> op;
for (int i = 0; i < n; i++) {
while (a[i] < b[i]) {
for (int j = i + 1; j < n; j++) {
if (a[j] > b[j]) {
--a[j], ++a[i];
op.emplace_back(j, i);
break;
}
}
}
while (a[i] > b[i]) {
for (int j = i + 1; j < n; j++) {
if (a[j] < b[j]) {
--a[i], ++a[j];
op.emplace_back(i, j);
break;
}
}
}
}
cout << op.size() << "\n";
for (auto [x, y] : op) {
cout << x + 1 << ' ' << y + 1 << "\n";
}
}
return 0;
}
B. AquaMoon and Stolen String
題意
有 \(n\) 個字串,將 \(n - 1\) 個字串中同一位上的字元相互交換,給出原來的 \(n\) 個字串和操作後的 \(n - 1\) 個字串,找出那個未被操作的字串。
題解
將同一位上的字元異或相消,最後剩下的就是未被操作字串的字元。
程式碼
#include <bits/stdc++.h>
using namespace std;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n, m;
cin >> n >> m;
string ans(m, 0);
for (int i = 0; i < 2 * n - 1; i++) {
string s;
cin >> s;
for (int j = 0; j < m; j++) {
ans[j] ^= s[j];
}
}
cout << ans << "\n";
}
return 0;
}
C. AquaMoon and Strange Sort
題意
給出 \(n\) 個數,初始時均朝右(朝向不影響數值大小),每次操作可以選取相鄰的兩個數交換位置並反轉朝向,判斷能否將 \(n\) 個數排為升序後仍都朝右。
題解
若一個數操作後仍朝右,那麼它移動的距離一定是 2 的倍數,即位置的奇偶性不變,判斷排序前後同一值的奇偶位置個數是否相同即可。
程式碼
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e5 + 10;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; i++) {
cin >> a[i];
}
vector<vector<int>> pos_before(N, vector<int> (2));
for (int i = 0; i < n; i++) {
++pos_before[a[i]][i & 1];
}
sort(a.begin(), a.end());
vector<vector<int>> pos_after(N, vector<int> (2));
for (int i = 0; i < n; i++) {
++pos_after[a[i]][i & 1];
}
cout << (pos_before == pos_after ? "Yes" : "No") << "\n";
}
return 0;
}
D. AquaMoon and Chess
題意
給出一個 01 串,每個 1 只能隔著一個 1 與 0 交換位置,計算 01 串最終可能狀態的個數。
題解
將相鄰的兩個 1 看作一個整體,設 0 的個數為 \(n\) ,無交集的 11 個數為 \(m\) ,答案即 \(C_{n + m}^{m}\) 。
在奇數長度的連續 1 串中,有一個 1 因為無法移動,在所有可能狀態中的位置都是固定的。
程式碼
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e6 + 100;
constexpr int MOD = 998244353;
int fac[N], inv[N];
int binpow(int a, int b) {
int res = 1;
while (b) {
if (b & 1) res = 1LL * res * a % MOD;
a = 1LL * a * a % MOD;
b >>= 1;
}
return res;
}
int C(int n, int m){
if(m < 0 or m > n) return 0;
return 1LL * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}
void Init(){
fac[0] = 1;
for (int i = 1; i < N; i++) fac[i] = 1LL * fac[i - 1] * i % MOD;
inv[N - 1] = binpow(fac[N - 1], MOD - 2);
for (int i = N - 2; i >= 0; i--) inv[i] = 1LL * inv[i + 1] * (i + 1) % MOD;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
Init();
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
string s;
cin >> s;
int one = 0;
for (int i = 0; i + 1 < n; i++) {
if (s[i] == '1' and s[i + 1] == '1') {
++one, ++i;
}
}
int zero = count(s.begin(), s.end(), '0');
cout << C(one + zero, one) << "\n";
}
return 0;
}
參考
https://codeforces.com/blog/entry/92739
後記
蠻有思維難度的一場比賽,學到很多 ( ̄▽ ̄) /