VP Codeforces Round 908 (Div. 2)
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";
}