VP Educational Codeforces Round 4


A. The Text Splitting

题意:给你一个字符串,你要把它分成若干个长度为\(p\)或者长度为\(q\)的字符串。

考虑枚举分成几个长度为\(p\)的字符串,剩下长度是\(q\)的倍数则合法。

点击查看代码
void solve() {
	int n, a, b;
	std::cin >> n >> a >> b;
	std::string s;
	std::cin >> s;
	for (int i = 0; i <= n / a; ++ i) {
		if ((n - i * a) % b == 0) {
			std::cout << i + (n - i * a) / b << "\n";
			int j = 0;
			for (; j < i * a; j += a) {
				std::cout << s.substr(j, a) << "\n";
			}

			for (; j < n; j += b) {
				std::cout << s.substr(j, b) << "\n";
			}
			return;
		}
	}

	std::cout << -1 << "\n";
}

B. HDD is Outdated Technology

题意:给你一个排列,你要按顺序从\(1\)走到\(n\),每次代价是两个位置坐标的差的绝对值,求总代价。

记录每个数出现的位置,然后从小到大记录。

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

    i64 ans = 0;
    for (int i = 2; i <= n; ++ i) {
    	ans += std::abs(a[i] - a[i - 1]);
    }

    std::cout << ans << "\n";
}

C. Replace To Make Regular Bracket Sequence

题意:有四种左括号和右括号,每种类型的括号匹配形成一个合法的序列,你可以把任意一个括号变成另一个同左右类型的括号,问最少改变几个括号使得序列合法。

每个右括号是和离自己最近的左括号匹配的,那么用栈存每个左括号,遇到一个右括号则判断是不是同一类型的左括号,不是则需要改变一次。

点击查看代码
void solve() {
    std::string s;
    std::cin >> s;
    std::stack<char> stk;
    std::map<char, char> mp;
    mp['}'] = '{';
    mp[']'] = '[';
    mp[')'] = '(';
    mp['>'] = '<';
    int ans = 0;
    for (auto & c : s) {
    	if (c == ')' || c == '}' || c == ']' || c == '>') {
    		if (stk.empty()) {
    			std::cout << "Impossible\n";
    			return;
    		}
    		if (stk.top() != mp[c]) {	
	    		++ ans;
    		}
    		stk.pop();
    	} else {
    		stk.push(c);
    	}
    }

    if (stk.size()) {
    	std::cout << "Impossible\n";
    	return;
    }

    std::cout << ans << "\n";
}

D. The Union of k-Segments

题意:给你\(n\)个区间,求有多少区间至少被\(k\)个区间覆盖。

用差分的思想,把一个区间变成两个贡献:\((l, 1), (r, -1)\),然后从大到小遍历,记录每次值大于等于\(k\)的段的最左端点,直到小于\(k\)时加入答案即可。

点击查看代码
void solve() {
    int n, k;
    std::cin >> n >> k;
    std::vector<std::pair<int, int>> a;
    for (int i = 0; i < n; ++ i) {
    	int l, r;
    	std::cin >> l >> r;
    	a.push_back({l, 1});
    	a.push_back({r + 1, -1});
    }

    std::sort(a.begin(), a.end());
    int sum = 0;
    int last = 2e9;
    std::vector<std::pair<int, int>> ans;
    for (auto & [x, v] : a) {
    	sum += v;
    	if (sum >= k) {
    		last = std::min(last, x);
    	} else {
    		if (last <= x) {
    			ans.push_back({last, x - 1});
    		}
    		last = 2e9;
    	}
    }

    std::cout << ans.size() << "\n";
    for (auto & [l, r] : ans) {
    	std::cout << l << " " << r << "\n";
    }
}

E. Square Root of Permutation

题意:一个排列进行\(q_i = q_{q_i}\)的变化后变成了\(p\),现在给你一个\(p\),求一个合法的\(q\)

对于\(q_i\),让\(i\)\(q_i\)连边,那么因为每个点正好是一个出度一个入度,所以会形成若干个环。然后模拟方向,这个环到了\(p\)里会被打乱,每个位置指向的数是原来它指向的数的指向的数。那么每个环会根据位置的奇偶分成两个环,但发现奇数环的最后一个点会把两个环连接起来,所以如果环的长度是奇数,那么只需要两个两个跳着走还原奇数位置和偶数位置上的数,就可以得到原来的环。如果是长度为偶数的环,它会变成两个长度一样的环,那么可以两两匹配,一个环当成奇数位置的环一个环当成偶数位置的环,就可以用还原原来的环,如果没有匹配的则无解。

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

    std::vector<int> b(n + 1), vis(n + 1);
    std::vector<int> pre(n + 1);
    for (int i = 1; i <= n; ++ i) {
    	if (!vis[i]) {
    		std::vector<int> c;
    		while (!vis[i]) {
    			vis[i] = 1;
    			c.push_back(i);
    			i = a[i];
    		}

    		int m = c.size();
    		if (m & 1) {
    			std::vector<int> d(m);
    			for (int j = 0, k = 0; j < m; k = (k + 2) % m, ++ j) {
    				d[k] = c[j];
    			}

    			for (int j = 0; j < m; ++ j) {
    				b[d[j]] = d[(j + 1) % m];
    			}
    		} else {
    			if (pre[m]) {
    				std::vector<int> d(m * 2);
    				for (int j = 0, x = i, y = pre[m]; j < m * 2; ++ j) {
    					if (j % 2 == 0) {
    						d[j] = x;
    						x = a[x];
    					} else {
    						d[j] = y;
    						y = a[y];
    					}
    				}

    				for (int j = 0; j < m * 2; ++ j) {
    					b[d[j]] = d[(j + 1) % (m * 2)];
    				}

    				pre[m] = 0;
    			} else {
    				pre[m] = i;
    			}
    		}
    	}
    }

    for (int i = 2; i <= n; i += 2) {
    	if (pre[i]) {
    		std::cout << -1 << "\n";
    		return;
    	}
    }

    for (int i = 1; i <= n; ++ i) {
    	std::cout << b[i] << " \n"[i == n];
    }
}

F. Simba on the Circle

待补

posted @ 2025-02-15 15:15  maburb  阅读(37)  评论(0)    收藏  举报