1382 A. Common Subsequence
题意:找出数组a和数组b共有的子序列。要求子序列长度最短。若不存在则输出’NO’
思路:最少的子序列长度就是1。所以只要两个数组中存在一个相同的数,输出即可。
#include<bits/stdc++.h>
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<bits/stdc++.h>
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<bits/stdc++.h>
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<bits/stdc++.h>
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<bits/stdc++.h>
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;
}