A - Secret Sport
题意:两个人比赛,每有一个人赢了\(X\)场就算它赢了一轮。比赛是在有一个人赢了\(Y\)轮后结束。你不知道\(XY\),但给你一个每场的输赢情况,求谁是赢家。
去求\(XY\)非常难,不如倒着想,一轮必然是因为赢的那个人赢了一把而结束,同样,整个比赛也是因为赢的那个人赢了一轮而结束。所有,最后一个赢得人就是赢家。
点击查看代码
void solve() {int n;std::cin >> n;std::string s;std::cin >> s;std::cout << s.back() << "\n";
}
B. Two Out of Three
题意:题意,给你一个\(a\),你要构造一个\(b\)使得正好满足三个条件其中得任意两个。
- 有一个 \(1 \leq i, j \leq n\) 使得 \(a_i = a_j\), \(b_i = 1\), \(b_j = 2\).
- 有一个 \(1 \leq i, j \leq n\) 使得 \(a_i = a_j\), \(b_i = 1\), \(b_j = 3\).
- 有一个 \(1 \leq i, j \leq n\) 使得 \(a_i = a_j\), \(b_i = 2\), \(b_j = 3\).
对于每一类数,他们只能由两个不同的值,否则就会同时满足三个条件。那么让每个个数大于等于\(2\)的数字满足一个条件,只需要两个就可以满足两个条件,其他的全部赋值为\(1\)就行。
点击查看代码
void solve() {int n;std::cin >> n;std::vector<int> a(n);for (int i = 0; i < n; ++ i) {std::cin >> a[i];}std::map<int, std::vector<int> > mp;for (int i = 0; i < n; ++ i) {mp[a[i]].push_back(i);}std::vector<int> b(n, 1);int cnt = 0;for (auto & [x, a] : mp) {if (a.size() >= 2) {if (cnt == 0) {b[a[1]] = 2;} else if (cnt == 1) {b[a[1]] = 3;}++ cnt;} }if (cnt < 2) {std::cout << -1 << "\n";} else {for (int i = 0; i < n; ++ i) {std::cout << b[i] << " \n"[i == n - 1];}}
}
C. Anonymous Informant
题意:如果\(a_i = i\),则可以让\(a\)左移\(i\)次。现在给你一个数组\(b\),说他是由某个数组进行\(k\)次操作变过来的,判断对错。
模拟一下发现,因为\(a_i = i\),那么左移\(i\)次后\(a_i\)到了结尾。因为\(b\)是变过来的,那么它的最后一个数就代表上一次左移了几位,那我们可以不断右移反着回去,如果某一次出现操作的数大于\(n\),可能无解,如果有一个位置出现两次,说明有环,我们在环上必然可以选一个起点使得它操作\(k\)次变成\(b\)。我们模拟\(\min(n, k)\)次即可。因为\(n\)次必然会出现一个环,否则我们\(k < n\)并且可以操作\(n\)次以上,一定有一个数组可以通过\(k\)次操作到\(b\)。
点击查看代码
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];}int x = 0;std::vector<int> st(n);st[0] = 1;for (int i = 0; i < std::min(n, k); ++ i) {if (a[n - 1 - x] > n) {std::cout << "NO\n";return;}x += a[n - 1 - x];x %= n;if (st[x]) {std::cout << "YES\n";return;}st[x] = 1;}std::cout << "YES" << "\n";
}
D. Neutral Tonality
做过最简单的\(d\)。
题意:给你两个数组\(a, b\),你要把\(b\)的每个数插到\(a\)的任意一个位置,让最后数组的最长子序列长度最短。
如果\(a_i > a_{i+1}\),那么我们是不是可以把\([a_{i+1}, a_i]\)的数都插到中间,这样不会使\(LIS\)变长。然后发现,好像就做完了。
点击查看代码
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];}std::vector<int> ans;std::sort(b.begin(), b.end(), std::greater<int>());int j = 0;for (int i = 0; i < n; ++ i) {while (j < m && b[j] >= a[i]) {ans.push_back(b[j ++ ]);}ans.push_back(a[i]);}while (j < m) {ans.push_back(b[j ++ ]);}for (int i = 0; i < n + m; ++ i) {std::cout << ans[i] << " \n"[i == n + m - 1];}
}
E. Freedom of Choice
题意:\(m\)个多重集,第\(i\)个多重集有\(n_i\)个数,每个数有\(c_i\)个。你要从每个集合里选数,选的个数在\([l_i, r_i]\)之间。定义集合的价值为在集合内且等于集合元素个数的元素数量。
我们可以枚举选\(i\)数,那么尽量不要选\(i\)这个数字。每个数字模拟一下取最小值就行。
点击查看代码
void solve() {int m;std::cin >> m;std::map<i64, std::vector<std::pair<int, i64> > > mp;std::vector<std::array<i64, 4> > a(m);i64 suml = 0, sumr = 0;for (int i = 0; i < m; ++ i) {i64 n, l, r;std::cin >> n >> l >> r;suml += l, sumr += r;std::vector<i64> b(n), c(n);for (int j = 0; j < n; ++ j) {std::cin >> b[j];}for (int j = 0; j < n; ++ j) {std::cin >> c[j];}i64 tot = 0;for (int j = 0; j < n; ++ j) {mp[b[j]].push_back({i, c[j]});tot += c[j];}a[i] = {n, l, r, tot};}for (i64 i = suml; i <= sumr; ++ i) {if (!mp.count(i)) {std::cout << 0 << "\n";return;}}i64 ans = 1e18;for (i64 i = suml; i <= sumr; ++ i) {i64 sum = sumr, res = 0;for (auto & [id, cnt] : mp[i]) {auto & [n, l, r, tot] = a[id];sum -= r;if (tot - cnt < l) {res += l - (tot - cnt);sum += l;} else {sum += std::min(r, tot - cnt);}}res += std::max(0ll, i - sum);ans = std::min(ans, res);}std::cout << ans << "\n";
}