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";
}
posted @ 2025-05-07 17:53  maburb  阅读(9)  评论(0)    收藏  举报