Educational Codeforces Round 179 (Rated for Div. 2)


A. Energy Crystals

题意:三个数,每次操作使得一个数增加任意数。但要保证任意两个数都有一个数大于等于另一个数的一半。求三个数都变成\(x\)的最少操作数。

首先把一个数变成\(1\),那么发现,之后没操作两步就能使得最大值乘二加一。那么需要\(log_2x \times 2\)的操作数把最大值变成\(x\),然后两次操作把另外两个数变成\(x\),加上一开始的一步,就是\(log_2x \times 2+3\)

点击查看代码
void solve() {
    int x;
    std::cin >> x;
    std::cout << std::__lg(x) * 2 + 3 << "\n";
}

B. Fibonacci Cubes

题意:有\(n\)个立方体,其中第\(i\)个边长为\(f_i\)\(f\)是斐波拉契数列的值。\(m\)次询问,问一个\(w\times l\times h\)的盒子能不能放下所有立方体。每个立方体不能有地方悬空,要么放在地面上要么放在另一个立方体上。

首先如果\(w, l, h\)中有一个小于\(f_n\),则无解。
否则如果\(h \geq f_n + f_{n-1}\),我们知道\(f_n = f_{n-1} + f_{n-2}\),那么可以把第\(n-1,n-2\)个立方体都放在第\(n\)个立方体上面,空出的另一半可以放\(f_{n-3},f_{n-4}\)...,依次类推,可以放完所有立方体。
如果\(max(w - f_n, l - f_n) > f_{n-1}\),则同理可以放完所有立方体。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<int> f(n + 1);
    f[1] = 1, f[2] = 2;
    for (int i = 3; i <= n; ++ i) {
    	f[i] = f[i - 1] + f[i - 2];
    }

    while (m -- ) {
    	int w, l, h;
    	std::cin >> w >> l >> h;
    	if (w < f[n] || l < f[n] || h < f[n]) {
    		std::cout << "0";
    		continue;
    	}

    	if (f[n] + f[n - 1] <= h || w - f[n] >= f[n - 1] || l - f[n] >= f[n - 1]) {
	    	std::cout << "1";
    	} else {
    		std::cout << "0";
    	}
    }
    std::cout << "\n";
}

C. Equal Values

题意:给你一个数组\(a\),每次选择一个\(i\),花费\((i-1)\times a_i\)把左边都变成\(a_i\),或者花费\((n-i)\times a_i\)把右边都变成\(a_i\)。求数组所有数相同的最小花费。

要么操作第一个数把右边都变成它,要么操作最后一个数把左边都变成它,要么选两个相同的数操作。
选两个数也有两种操作,假设选了\(i, j\),那么可以操作\(i\)的右边和\(j\)的左边,显然应该选最近的两个相同的数。如果\([i, j]\)之间的数都相同,那么可以操作\(i\)的左边和\(j\)右边。
所有情况取最小值就行。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::vector<i64> a(n + 1);
    for (int i = 1; i <= n; ++ i) {
    	std::cin >> a[i];
    }

    if (std::ranges::count(a, a[1]) == n) {
    	std::cout << 0 << "\n";
    	return;
    }

    i64 ans = std::min(a[1], a[n]) * (i64)(n - 1);
    std::vector<int> last(n + 1);
    for (int i = 1; i <= n; ++ i) {
    	if (last[a[i]]) {
    		ans = std::min(ans, ((i64)n - last[i] + i - 1) * a[i]);
    	}
    	ans = std::min(ans, ((i64)n - i + i - 1) * a[i]);
    	last[a[i]] = i;
    }

    for (int i = 1; i <= n; ++ i) {
    	int j = i;
    	while (j + 1 <= n && a[j + 1] == a[i]) {
    		++ j;
    	}

    	ans = std::min(ans, ((i64)i - 1 + n - j) * a[i]);
    	i = j;
    }
    std::cout << ans << "\n";
}

D. Creating a Schedule

题意:用给定的\(m\)个数填一个\(n\times 6\)的矩阵,使得每列没有相同的数。其价值定义为每行相邻两个数去除末尾两位后的差的绝对值。求价值最大的矩阵。

如果给你恰好\(n\)个数,那么应该按列先从小到大填,然后从大到小填,这样循环。这样的价值是最大的,可以把每对相邻点想象为一条线段,线段的长度就是这两个数产生的价值,那么我们应该尽可能让长的的线段多,于是这样排列就能保证最大。考虑有多于\(n\)个数的情况,我们应该选前\(n / 2\)个最小的和后\(n / 2\)个最大的,如果\(n\)是奇数,它可以选剩下的数里最大的最小的循环交替出现。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::vector<i64> a(m);
    for (int i = 0; i < m; ++ i) {
    	std::cin >> a[i];
    }

    std::ranges::sort(a);
    std::vector<i64> b;
    int l = 0, r = m - 1;
    for (; l < r; ++ l, -- r) {
    	if (b.size() + 2 <= n)  {
    		b.push_back(a[l]);
    		b.push_back(a[r]);
    	} else {
    		break;
    	}
    }

    std::ranges::sort(b);
    std::vector ans(n, std::array<i64, 6>{});
    for (int j = 0; j < 6; ++ j) {
    	if (j & 1) {
    		for (int i = 0, k = 0; i < n; ++ i) {
    			if (n % 2 && i == n / 2) {
    				ans[i][j] = a[l];
    			} else {
	    			ans[i][j] = b[k ++ ];
    			}
    		}
    	} else {
    		for (int i = n - 1, k = 0; i >= 0; -- i) {
    			if (n % 2 && i == n / 2) {
    				ans[i][j] = a[r];
    			} else {
	    			ans[i][j] = b[k ++ ];
    			}
    		}
    	}
    }

    for (int i = 0; i < n; ++ i) {
    	for (int j = 0; j < 6; ++ j) {
    		std::cout << ans[i][j] << " \n"[j == 5];
    	}
    }
}

E. Changing the String

题意:给你一个只包含\(a, b, c\)的字符串,有\(m\)次操作,每次让你把一类字符的一个变成另一个字符。你也可以无视任意这个操作。求最小字典序。

要想字典序最小,我们可以从前往后考虑,让前面的尽可能小。
如果\(s[i] = a\),不进行操作。
如果\(s[i] = b\),那么优先\(b\)->\(a\)其次是\(b\)->\(c\)->\(a\)
如果\(s[i] = c\),那么优先\(c\)->\(a\),其次是\(c\)->\(b\)->\(a\),再就是\(c\)->\(b\)
那么我们可以\(set\)记录每个操作的位置,\(S[i][j]\)记录了\(i\)->\(j\)的所有操作的下标。那么只需要从前往后模拟,按优先级处理,每次用最前的操作,注意\(b\)->\(c\)->\(a\)这种需要\(c\)->\(a\)的操作位置在\(b\)->\(c\)操作的后面,可以用set的lower_bound查找。

点击查看代码
void solve() {
    int n, m;
    std::cin >> n >> m;
    std::string s;
    std::cin >> s;
    std::set<int> S[3][3]{};
    for (int i = 0; i < m; ++ i) {
    	char a, b;
    	std::cin >> a >> b;
    	S[a - 'a'][b - 'a'].insert(i);
    }

    for (int i = 0; i < n; ++ i) {
    	if (s[i] == 'a') {
    		continue;
    	}

    	if (s[i] == 'b') {
    		if (S[1][0].empty()) {
    			if (S[1][2].empty()) {
    				continue;
    			}

    			auto it = S[2][0].lower_bound(*S[1][2].begin());
    			if (it != S[2][0].end()) {
    				s[i] = 'a';
    				S[1][2].erase(S[1][2].begin());
    				S[2][0].erase(it);
    			}
    		} else {
    			s[i] = 'a';
    			S[1][0].erase(S[1][0].begin());
    		}
    	} else {
    		if (S[2][0].empty()) {
    			if (S[2][1].size()) {
    				s[i] = 'b';
    				auto it = S[1][0].lower_bound(*S[2][1].begin());
    				if (it != S[1][0].end()) {
    					s[i] = 'a';
    					S[1][0].erase(it);
    				}
    				S[2][1].erase(S[2][1].begin());
    			}
    		} else {
    			s[i] = 'a';
    			S[2][0].erase(S[2][0].begin());
    		}
    	}

    }

    std::cout << s << "\n";
}
posted @ 2025-06-04 01:14  maburb  阅读(503)  评论(7)    收藏  举报