Codeforces Round #658 (Div. 2) A、B、C1、C2、D题解

1382 A. Common Subsequence

题意:找出数组a和数组b共有的子序列。要求子序列长度最短。若不存在则输出’NO’

思路:最少的子序列长度就是1。所以只要两个数组中存在一个相同的数,输出即可。

#include
using namespace std;
int main() {
	ios::sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--) {
		int n, m;
		cin >> n >> m;
		vector<int> a(2000);
		vector<int> b(2000);
		int i;
		int num;
		for (i = 0; i < n; i++) {
			cin >> num;
			a[num] = 1;
		}
		for (i = 0; i < m; i++) {
			cin >> num;
			b[num] = 1;
		}
 
		int ans = num;
		int flag = 0;
		for (i = 1; i <= 1000; i++) {
			if (a[i] && b[i]) {
				ans = i;
				flag = 1;
				break;
			}
		}
 
		if (flag) {
			cout << "YES" << endl;
			cout <<1<<' '<< ans << endl;
		}
		else {
			cout << "NO" << endl;
		}
	}
	return 0;
}

1382 B. Sequential Nim

题意:有n个石堆,每个石堆有ai个石块。两个玩家每次可以从下标最小的非空石堆中拿走人一个石块(最少要拿一个)。最后没有石块拿的人就输了。

思路:这题先手是必赢。但是前导数量为1的石堆。会影响谁才是真的先手。

#include
using namespace std;
int main() {
	ios::sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		vector<int> v(n);
		int i;
		int a = 0;
		int cnt = 0;
		for (i = 0; i < n; i++) {
			cin >> v[i];
 
		}
		int flag = 1;
		for (i = n - 2; i >= 0; i--) {
			if (v[i] == 1) {
				flag = 1 - flag;
			}
			else {
				flag = 1;
			}
		}
		if (flag) {
			cout << "First\n";
		}
		else {
			cout << "Second\n";
		}
		
	}
	return 0;
}

1382 C1. Prefix Flip (Easy Version)

题意:有两个字符串a和b。仅包含0或者1。可以对字符串进行一下操作。选取前a个字符同时把0变成1,1变成0,之后最这个长度为a的字串进行反转。要你字符串a转变成b。输出每次操作的步骤。

思路:既然是C1。数据比较弱,那就先暴力判断一波。每次用a字符串的第一个字符和b字符串的最后一个字符进行判断。如果不相等。则翻转整个a字符串。然后两个字符串长度减一。如果相等的话,就先对a的第一个字符进行反转操作。然后再反转整个a。

#include
using namespace std;
int main() {
	ios::sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		string str1;
		string str2;
		cin >> str1 >> str2;
		int i, j;
		i = 0;
		j = n - 1;
		int flag = 1;
		for (i = 0; i < n; i++) {
			if (str1[i] != str2[i]) {
				flag = 0;
			}
		}
		
		vector<int> ans;
		i = 0;
		j = n - 1;
		while (j >= 0) {
			int k = 1;
			if (str2[j] == str1[0]) {
				ans.push_back(1);
				k = 0;
			}
			for (k; k < str2.size() - i; k++) {
				if (str1[k] == '0') {
					str1[k] = '1';
				}
				else {
					str1[k] = '0';
				}
			}
			reverse(str1.begin(), str1.end() - i);
			ans.push_back(str2.size() - i);
			i++;
			j--;
		}
		cout << ans.size() ;
		for (i = 0; i < ans.size(); i++) {
			cout << ' ' << ans[i];
		}
		cout << endl;
	}
	return 0;
}

1382 C2. Prefix Flip (Hard Version)

题意:见C1

思路:这题n的数据开到1e5了,如果还手动模拟反转操作的话,复杂度为n方。肯定是过不去的。所以这里并不能真的去进行反转。

仔细观察一下在C1中每次比较的时候都是拿b串的最后一个字符与a的第一个字符进行比较。而且每次整体至少会反转一次。那么我们只要确定每次反转后。a的第一个字符是原字符串的那个字符即可。

比如长度为6的字符串。每次反转后第一个字符的下标为 0 5 1 4 2 3。

然后用个变量计算一下反转的次数。如果反转一次 ‘0’跟1异或为‘1’ 。‘1’跟1异或为’0’。

#include
using namespace std;
int main() {
	ios::sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--) {
		int n;
		cin >> n;
		string str1;
		string str2;
		cin >> str1 >> str2;
		int i, j;
		i = 0;
		j = n - 1;
		int flag = 1;
		for (i = 0; i < n; i++) {
			if (str1[i] != str2[i]) {
				flag = 0;
			}
		}
		vector<int> idx;
		i = 0;
		j = n - 1;
		while (i <= j) {
			if (i != j) {
				idx.push_back(i);
				idx.push_back(j);
			}
			else {
				idx.push_back(i);
			}
			i++; j--;
		}
		vector<int> ans;
		j = n - 1;
		int cnt = 0;
		while (j >= 0) {
			if (str2[j] != (str1[idx[cnt] ]^ (cnt % 2))) {
				ans.push_back(j+1);
			}
			else {
				ans.push_back(1);
				ans.push_back(j+1);
			}
			cnt++;
			j--;
		}
		cout << ans.size() ;
		for (i = 0; i < ans.size(); i++) {
			cout << ' ' << ans[i];
		}
		cout << endl;
	}
	return 0;
}

1382 D. Unmerge

赛后把D题补了。其实仔细看了下并没有想象中那么难。

题意:由一个递归的定义取合并两个数组a,b

  • 如果其中一个数组为空,则结果是另一个数组。也就是,归并(∅,b)=b,归并(a,∅)=a。特别是,(∅,∅)=∅合并。
  • 如果两个数组都是非空的,且a1也就是说,我们删除a的第一个元素a1,合并剩下的数组,然后将a1添加到结果的开始部分。
  • 如果两个数组都是非空的,且a1>b1,则merge(a,b)=[b1]+merge(a,[b2,…,bm])。也就是说,我们删除b的第一个元素b1,合并剩下的数组,然后在结果的开头加上b1。
    给一个含有2*n个元素排列。确定是否存在两个数组a和b,每个数组的长度为n,并且没有相同的元素,使得p=merge(a,b)。
    思路:把数组p分成k段连续递减的连续子序列。用背包判断这些子序列长度是否可以组成一个长度为n 的数组。
#include
using namespace std;
 
int flag = 0;
vector<int> ans;
int n;
 
 
int main() {
	ios::sync_with_stdio(false);
	int t;
	cin >> t;
	while (t--) {
		flag = 0;
		cin >> n;
		vector<int>v(n*2);
		int i, j;
		for (i = 0; i < 2*n; i++) {
			cin >> v[i];
		}
		ans.clear();
		for (i = 0; i < 2*n; i++) {
			int first = v[i];
			vector<int> tmp;
			tmp.push_back(first);
			i++;
			while (i<2 * n && first>v[i]) {
				tmp.push_back(v[i]);
				i++;
			}
			ans.push_back(tmp.size());
			i--;
		}
		vector<bool> vis(4000);
		vis[0] = true;
		for (i = 0; i < ans.size(); i++) {
			for (j = n; j >= ans[i]; j--) {
				if (!vis[j] && vis[j - ans[i]]) {
					vis[j] = true;
				}
			}
		}
		if (vis[n]) {
			cout << "YES" << endl;
		}
		else {
			cout << "NO" << endl;
		}
 
	}
	return 0;
}

你可能感兴趣的:(codeforces,ACM)