VP Educational Codeforces Round 70 (Rated for Div. 2)


A. You Are Given Two Binary Strings...

题意:给你两个二进制串\(x, y\),要求把\(y\)左移\(k\)位后和\(x\)相加然后翻转后的二进制串在字典序下最小,求最小的\(k\)

为了让翻转后二进制字典序最小,应该让低位尽可能是零,那么应该人\(y\)的最低的\(1\)\(x\)中一个\(1\)相加。找可以和它相加的最近的那个\(1\)位置。看要位移几位。

点击查看代码
void solve() {
    std::string s, t;
    std::cin >> s >> t;
    std::ranges::reverse(s);
    std::ranges::reverse(t);
    int p = t.find('1');
    std::vector<int> pos;
    for (int i = 0; i < s.size(); ++ i) {
    	if (s[i] == '1') {
    		pos.push_back(i);
    	}
    }
    
    auto it = std::ranges::lower_bound(pos, p);
    std::cout << std::abs(*it - p) << "\n";
}

B. You Are Given a Decimal String...

题意:对于一个\(x, y\),你只能每次加上\(x\)\(y\)。然后当前和的个位数会被打印出来。你被给出一个打印序列,求对于每个\(x, y\)最少插入几个字符可以满足条件。

其它就是求在限定\(x, y\)的情况下,从个位数位\(x\)加到个位数变成\(y\)需要加几次。可以用\(bfs\)求。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;

    auto get = [&](int x, int y) -> int {
    	std::array<std::array<int, 10>, 10> d{};
    	for (int i = 0; i < 10; ++ i) {
    		for (int j = 0; j < 10; ++ j) {
    			d[i][j] = -1;
    		}
    	}

    	for (int i = 0; i < 10; ++ i) {
    		std::queue<int> q;
    		q.push((i + x) % 10);
    		d[i][(i + x) % 10] = 0;
    		q.push((i + y) % 10);
    		d[i][(i + y) % 10] = 0;
    		while (q.size()) {
    			int u = q.front(); q.pop();
    			if (d[i][(u + x) % 10] == -1) {
    				d[i][(u + x) % 10] = d[i][u] + 1;
    				q.push((u + x) % 10);
    			}

    			if (d[i][(u + y) % 10] == -1) {
    				d[i][(u + y) % 10] = d[i][u] + 1;
    				q.push((u + y) % 10);
    			}
    		}
    	}

    	int res = 0;
    	for (int i = 0; i + 1 < s.size(); ++ i) {
    		if (d[s[i] - '0'][s[i + 1] - '0'] == -1) {
    			return -1;
    		}
    		res += d[s[i] - '0'][s[i + 1] - '0'];
    	}
    	return res;
    };

    for (int i = 0; i < 10; ++ i) {
    	for (int j = 0; j < 10; ++ j) {
    		std::cout << get(i, j) << " \n"[j == 9];
    	}
    }
}

C. You Are Given a WASD-string...

题意:给你四个方向的移动序列。记移动中\(max_x, min_x, max_y, min_y\)分别为到的最大最小的\(x, y\)下标,那么代价为\((max_x - min_x + 1) \times (max_y - min_y + 1)\)。你现在可以最多插入一个移动,求最小代价。

行和列可以分开考虑。
考虑行怎么做,列同理。我们希望\(max_x\)可以减少\(1\),或者\(min_x\)可以增大\(1\)。直接加减是不对的,因为你需要进行一次相反操作,这可以使得另一个最值变化。但想要使得最大值变小或者最小值变大,肯定是在它第一次达到的位置操作,那么可以对每个情况模拟。

点击查看代码
void solve() {
	std::string s;
	std::cin >> s;
	i64 maxx = 0, minx = 0, maxy = 0, miny = 0;
	i64 maxx1 = 0, minx1 = 0, maxy1 = 0, miny1 = 0;
	i64 maxx2 = 0, minx2 = 0, maxy2 = 0, miny2 = 0;
	i64 x = 0, y = 0;
	for (auto & c : s) {
		if (c == 'W') {
			-- x;
		} else if (c == 'S') {
			++ x;
		} else if (c == 'D') {
			++ y;
		} else {
			-- y;
		}

		maxx = std::max(maxx, x);
		minx = std::min(minx, x);
		maxy = std::max(maxy, y);
		miny = std::min(miny, y);
	}

	bool flagx1 = true, flagx2 = true, flagy1 = true, flagy2 = true;;
	x = 0, y = 0;
	for (auto & c : s) {
		if (c == 'W') {
			-- x;
		} else if (c == 'S') {
			++ x;
		} else if (c == 'D') {
			++ y;
		} else {
			-- y;
		}

		if (x == maxx && flagx1) {
			flagx1 = false;
			-- x;
			minx1 = std::min(minx, x - 1);
		}
		maxx1 = std::max(maxx1, x);
		minx1 = std::min(minx1, x);
	}

	x = 0, y = 0;
	for (auto & c : s) {
		if (c == 'W') {
			-- x;
		} else if (c == 'S') {
			++ x;
		} else if (c == 'D') {
			++ y;
		} else {
			-- y;
		}

		if (x == minx && flagx2) {
			flagx2 = false;
			++ x;
			maxx2 = std::max(maxx, x + 1);
		} 
		maxx2 = std::max(maxx2, x);
		minx2 = std::min(minx2, x);
	}

	x = 0, y = 0;
	for (auto & c : s) {
		if (c == 'W') {
			-- x;
		} else if (c == 'S') {
			++ x;
		} else if (c == 'D') {
			++ y;
		} else {
			-- y;
		}

		if (y == maxy && flagy1) {
			flagy1 = false;
			-- y;
			miny1 = std::min(miny, y - 1);
		}
		maxy1 = std::max(maxy1, y);
		miny1 = std::min(miny1, y);
	}

	x = 0, y = 0;
	for (auto & c : s) {
		if (c == 'W') {
			-- x;
		} else if (c == 'S') {
			++ x;
		} else if (c == 'D') {
			++ y;
		} else {
			-- y;
		}

		if (y == miny && flagy2) {
			flagy2 = false;
			++ y;
			maxy2 = std::max(maxy, y + 1);
		} 
		maxy2 = std::max(maxy2, y);
		miny2 = std::min(miny2, y);
	}

	i64 lenx = maxx - minx + 1, leny = maxy - miny + 1;
	i64 lenx1 = maxx1 - minx1 + 1, leny1 = maxy1 - miny1 + 1;
	i64 lenx2 = maxx2 - minx2 + 1, leny2 = maxy2 - miny2 + 1;
	i64 ans = std::min({lenx1 * leny, lenx * leny1, lenx2 * leny, lenx * leny2, lenx * leny});
	std::cout << ans << "\n";
}

D. Print a 1337-string...

题意:构造一个长度不超过\(1e5\)且有\(n\)\(1337\)作为子序列的字符串。

考虑左边一个\(1\),中间\(m\)\(3\),右边一个\(7\),那么有\(\frac{m(m-1)}{2}\)\(1337\)。我们找到最接近\(n\)的这个数,然后在\(133\)后面插入\(n - \frac{m(m-1)}{2}\)\(7\)就行。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    i64 m = 1;
    while (m * (m - 1) / 2 <= n) {
    	++ m;
    }

    -- m;
    std::string ans;
    ans += "133";
    ans += std::string(n - m * (m - 1) / 2, '7');
    ans += std::string(m - 2, '3');
    ans += '7';
    std::cout << ans << "\n";
}
posted @ 2025-04-28 17:14  maburb  阅读(18)  评论(0)    收藏  举报