• Codeforces Global Round 11【ABCD】


    比赛链接:https://codeforces.com/contest/1427

    A. Avoiding Zero

    题意

    (n) 个数重新排列使得不存在为 (0) 的前缀和。

    题解

    计算正、负前缀和,如果二者和为 (0),则不存在满足题意的排列,否则将绝对值较大的一方排在前面即可。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	int t;
    	cin >> t;
    	while (t--) {
    		int n;
    		cin >> n;
    		vector<int> a(n);
    		int pos = 0, neg = 0;
    		for (auto &x : a) {
    			cin >> x;
    			(x < 0 ? neg : pos) += x;
    		}
    		if (pos + neg == 0) {
    			cout << "NO" << "
    ";
    			continue;
    		}
    		if (pos + neg > 0) {
    			sort(a.begin(), a.end(), greater<>());
    		} else {
    			sort(a.begin(), a.end(), less<>());
    		}
    		cout << "YES" << "
    ";
    		for (int i = 0; i < n; i++) {
    			cout << a[i] << " 
    "[i == n - 1];
    		}
    	}
    	return 0;
    }
    

    B. Chess Cheater

    题意

    给出一个长为 (n) 由 W, L 组成的字符串,如果一个 W 左侧为 W,则它提供 2 分,否则为 1 分。最多可以将 (k) 个 L 变为 W,问字符串可以得到的最大分值。

    题解

    本题的关键是字符串中 W 的有无及两两构成的封闭区间长度。

    • 如果全为 L,则字符串的最大分值为 (max(2k-1, 0))
    • 如果存在 W,则每次操作都会至少增加 2 分,如果操作的为两个 W 区间内的最后一个 L,则会额外再增加 1 分。
      所以计算字符串的初始分值,加上 (2 imes min(k, cntL)) 分,然后区间长度排序,每当可以减去一个完整区间长就再加上 1 分。

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	int t;
    	cin >> t;
    	while (t--) {
    		int n, k;
    		cin >> n >> k;
    		string s;
    		cin >> s;
    		int cntL = count(s.begin(), s.end(), 'L');
    		if (cntL == n) {
    			cout << max(2 * k - 1, 0) << "
    ";
    			continue;
    		}
    		vector<int> posW;
    		for (int i = 0; i < n; i++)
    			if (s[i] == 'W') posW.push_back(i);
    		vector<int> seg;
    		for (int i = 1; i < int(posW.size()); i++)
    			if (posW[i] - posW[i - 1] - 1 > 0) seg.push_back(posW[i] - posW[i - 1] - 1);
    		int ans = s[0] == 'W';
    		for (int i = 1; i < n; i++) 
    			if (s[i] == 'W') ans += s[i - 1] == 'W' ? 2 : 1;
    		ans += 2 * min(k, cntL);
    		sort(seg.begin(), seg.end());
    		for (auto len : seg) if (k >= len) k -= len, ans += 1;
    		cout << ans << "
    ";
    	}
    	return 0;
    }
    

    C. The Hard Work of Paparazzi

    题意

    (r) 行与 (r) 列相交形成了 (r imes r) 个点,初始时刻记者位于左下角的 ((1,1)) 处,接下来给出 (n) 个名人的出现时间和位置,出现时间严格递增,问记者最多可以拍到多少名人的照片。
    示例

    题解

    This is a classical dynamic-programming task with a twist.
    这是一个有些变化的经典动态规划问题。

    与最长上升子序列问题的不同之处的是,本题判断条件由 (a_j > a_i) 变为了 (dis_{ij} le t_j - t_i) 以及利用 (r)(O_{(n^2)}) 优化至了 (O_{(nr)})

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	int r, n;
    	cin >> r >> n;
    	//如果 r == 1,此时只有 1 个点
    	if (r == 1) {
    		cout << n << "
    ";
    		return 0;
    	}
    	vector<int> t(n + 1), x(n + 1), y(n + 1);
    	t[0] = 0, x[0] = 1, y[0] = 1;
    	for (int i = 1; i <= n; i++) 
    		cin >> t[i] >> x[i] >> y[i];
    	vector<int> dp(n + 1, -1e9), mx_dp(n + 1);
    	dp[0] = 0; //初始时只有时刻 0 的 (1,1) 可达
    	for (int i = 1; i <= n; i++) {
    		//继承之前可达的 dp 状态
    		for (int j = max(i - 2 * (r - 1), 0); j < i; j++) {
    			if (abs(x[i] - x[j]) + abs(y[i] - y[j]) <= t[i] - t[j])
    				dp[i] = max(dp[i], dp[j] + 1);
    		}
    		//如果 i 大于等于最长路径,那么对于 dp[0] ~ dp[i - 2 * (r - 1)] 一定是可达的
    		if (i >= 2 * (r - 1)) dp[i] = max(dp[i], mx_dp[i - 2 * (r - 1)] + 1);
    		mx_dp[i] = max(dp[i], mx_dp[i - 1]);
    	}
    	cout << mx_dp[n] << "
    ";
    	return 0;
    }
    

    D. Unshuffling a Deck

    题意

    给出一个大小为 (n) 的排列,每次操作可以将 (n) 个数分为 (1 sim n) 个非空连续份,然后将对称的份两两交换,试给出在 (n) 次操作内将排列排为升序的操作过程。

    题解

    1. 找到值相差为 (1) 的逆序对:(i<j)(a_i = a_j + 1)
    2. 将已为升序的数视为一个整体,找到 (t) 满足:(i le t < j)(a_t > a_{t+1})
    3. 分为 (4) 份,(D_1=[a_1,a_2,dots,a_{i-1}], D_2=[a_i,a_{i+1},dots, a_t], D_3=[a_{t+1},a_{t+2},dots, a_j], D_4=[a_{j+1},a_{j+2},dots, a_n])
    4. 将对称组交换,转至步骤 (1)

    代码

    #include <bits/stdc++.h>
    using namespace std;
    int main() {
    	ios::sync_with_stdio(false);
    	cin.tie(nullptr);
    	int n;
    	cin >> n;
    	vector<int> a(n), pos(n);
    	for (int i = 0; i < n; i++) {
    		cin >> a[i];
    		--a[i];
    	}
    	vector<vector<int>> ans;
    	while (not is_sorted(a.begin(), a.end())) {
    		for (int i = 0; i < n; i++) {
    			pos[a[i]] = i;
    		}
    		//1
    		for (int i = 1; i < n; i++) {
    			if (pos[i] < pos[i - 1]) {
    				//2
    				int l = pos[i];
    				int r = pos[i - 1];
    				int mid = l;
    				while (a[mid + 1] == a[mid] + 1) ++mid;
    				//3
    				ans.push_back({l, mid - l + 1, r - mid, n - r - 1});
    				//4
    				vector<int> b;
    				for (int i = r + 1; i < n; i++) b.push_back(a[i]);
    				for (int i = mid + 1; i < r + 1; i++) b.push_back(a[i]);
    				for (int i = l; i < mid + 1; i++) b.push_back(a[i]);
    				for (int i = 0; i < l; i++) b.push_back(a[i]);
    				a.swap(b);
    				break;
    			}
    		}
    	}
    	cout << ans.size() << "
    ";
    	for (auto &v : ans) {
    		//每份非空
    		while (v.back() == 0) v.pop_back();
    		while (v.front() == 0) v.erase(v.begin());
    		cout << v.size() << "
    ";
    		for (int i = 0; i < int(v.size()); i++) {
    			cout << v[i] << " 
    "[i == int(v.size()) - 1];
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    关于地址添加 子窗体向父窗体传值 树的使用详细
    C# 常见面试题2
    微软2014实习生及秋令营技术类职位在线测试
    【面试题004】c/c++字符串,替换空格
    【面试题003】c数组做为参数退化的问题,二维数组中的查找
    【面试题001】类型转换关键字,空类对象模型,拷贝构造函数,赋值运算符函数
    【面试题002】java实现的单例模式,c++实现单例模式,实现禁止拷贝
    【设计模式6原则总结】
    【设计模式六大原则6】开闭原则(Open Close Principle)
    【设计模式六大原则5】迪米特法则(Law Of Demeter)
  • 原文地址:https://www.cnblogs.com/Kanoon/p/13812550.html
Copyright © 2020-2023  润新知