VP Educational Codeforces Round 79 (Rated for Div. 2)
A. New Year Garland
题意:三种颜色分别有\(r, g, b\)个。求能不能把它们排成一行满足没有相邻的颜色相同。
只要\(max \leq \lceil \frac{r+g+b}{2} \rceil\)就满足。
点击查看代码
void solve() {
i64 a, b, c;
std::cin >> a >> b >> c;
int max = std::max({a, b, c});
if (max <= (a + b + c + 1) / 2) {
std::cout << "YES\n";
} else {
std::cout << "NO\n";
}
}
B. Verse For Santa
题意:一个序列,你需要从前往后取数,和不能超过\(s\),你可以选择跳过最多一个。求最多取多少数。
先预处理前缀和\(pre\)。那么如果取完了前\(i-1\)个想跳过第\(i\)个,那么则要最大的\(r\),满足\(pre[r] - pre[i] \leq s\),也就是\(pre[r] \leq s + pre[i]\)。可以二分找出。
点击查看代码
void solve() {
int n, s;
std::cin >> n >> s;
std::vector<int> a(n);
for (int i = 0; i < n; ++ i) {
std::cin >> a[i];
}
std::vector<i64> pre(n + 1);
for (int i = 0; i < n; ++ i) {
pre[i + 1] = pre[i] + a[i];
}
int ans = 0;
int max = std::max(0, (int)(std::ranges::upper_bound(pre, s) - pre.begin() - 1));
for (int i = 1; i <= n; ++ i) {
if (s <= 0) {
break;
}
//pre[r] - pre[i] <= s
//pre[r] <= s + pre[i]
int suf = std::max(0, (int)(std::ranges::upper_bound(pre, s + pre[i]) - pre.begin() - 1));
if (i - 1 + suf - i > max) {
max = i - 1 + suf - i;
ans = i;
}
s -= a[i - 1];
}
std::cout << ans << "\n";
}
C. Stack of Presents
题意:一个长度为\(n\)个排列\(a\),你需要依次取出\(m\)个数,第\(i\)次取出第\(b_i\)个数。每次只能从前往后取,也就是如果\(b_i\)的位置在\(p\),那么需要\(p\)次把这些数取出,然后把前面的\(p-1\)个数放回。但你放回时可以任意顺序放。求最少操作次数。
用一个集合表示被取出过的数,那么如果下一次要取的数在这些数里,我们就让上一次操作是把它放在最前面就行。否则我们需要把这些数在取出一次,然后剩下的数依次取到需要取的数,这些数也加入集合就行。
点击查看代码
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];
}
i64 ans = 0;
std::set<int> s;
for (int i = 0, j = 0; i < m; ++ i) {
if (!s.count(b[i])) {
ans += (int)s.size() * 2;
while (j < n && a[j] != b[i]) {
s.insert(a[j]);
++ j;
ans += 2;
}
ans += 1;
++ j;
} else {
ans += 1;
s.erase(b[i]);
}
}
std::cout << ans << "\n";
}
D. Santa's Bot
题意:\(n\)个集合\(a_i\)。第\(i\)个集合有\(k_i\)个数,第\(j\)个数为\(a_{i_j}\)。随机生成三个整数\(x, y, z\)。其中\(x \in [1, n], y\in [1, k_x], z \in [1, n]\)。求\(a_{x_y} \in a_z\)的概率。
取到\(a_{x_y}\)的概率为\(\frac{1}{n} \times \frac{1}{k_x}\)。把所有数的概率算出来,记为\(sum_i\)。
那么假设\(z\)是\(i\),则有\(\frac{1}{n}\)的概率取到。对于集合\(i\)的每个数\(a_{i_j}\),前面的\(x, y\)有\(sum_{i_j}\)的概率取到,那么概率就是\(\frac{1}{n} \times sum_{i_j}\)。则答案是\(\sum_{i=1}^{n} \sum_{j=1}^{k_i} \frac{1}{n} \times sum_{i_j}\)。
点击查看代码
const int mod = 998244353;
int power(int a, int b) {
int res = 1;
for (;b;b >>= 1, a = (i64)a * a % mod) {
if (b & 1) {
res = (i64)res * a % mod;
}
}
return res;
}
int inv(int n) {
return power(n, mod - 2);
}
void solve() {
int n;
std::cin >> n;
std::vector<std::vector<int>> a(n);
const int N = 1e6 + 5;
std::vector<int> sum(N);
for (int i = 0; i < n; ++ i) {
int k;
std::cin >> k;
while (k -- ) {
int x;
std::cin >> x;
a[i].push_back(x);
}
}
int ans = 0;
int invn = inv(n);
for (int i = 0; i < n; ++ i) {
int k = a[i].size();
int invk = inv(k);
for (auto & x : a[i]) {
sum[x] = (sum[x] + (i64)invn * invk % mod) % mod;
}
}
for (int i = 0; i < n; ++ i) {
int k = a[i].size();
int invk = inv(k);
for (auto & x : a[i]) {
ans = (ans + (i64)sum[x] * invn % mod) % mod;
}
}
std::cout << ans << "\n";
}

浙公网安备 33010602011771号