Codeforces Round #658 (Div. 2)
A. Common Subsequence
题意: 给定t个测试样例,每个测试样例给定一个n和m,分别表示数列1和数列2的长度,找出数列1和数列2的最短公共子序列。
题解: 最短公共子序列不是0就算1,有相同的字符为1,否则为0
代码:
#include <bits/stdc++.h>
using namespace std;
int const N = 1e3 + 10;
int a[N], b[N];
int t, n, m;
set<int> s;
int main() {
cin >> t;
while (t--) {
s.clear();
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
scanf("%d", &a[i]);
s.insert(a[i]);
}
int flg = 0;
for (int i = 1; i <= m; ++i) {
scanf("%d", &b[i]);
if (s.count(b[i])) {
flg = b[i];
}
}
if (flg == 0) {
cout << "NO
";
}
else {
cout << "YES
";
cout << 1 << " " << flg << endl;
}
}
return 0;
}
B. Sequential Nim
题意: 两个人玩博弈论游戏,有许多堆石头,每堆石头的数目都大于等于1,每次只能从第一堆石头取,可以取任意个正整数的石头,一旦不能取石头那么就输了。一开始第一个人先取,如果第一个人最后能赢,输出First;如果第二个人最后能赢,输出Second。(sum_{}n) <= 10^5^
题解: 如果当前石头数大于1,那么当前这个人可以选择是否交换先后手;如果当前石头数位1,那么当前这个人必须交换先后手。因此,一旦出现第一个大于n的石头数目,当前这个人就可以根据后面的石头数,找到最优策略,然后取胜(当前如果是k>1,那么可以根据后面的石头确定一种获胜状态),因此只需要计算出现第一个大于1的石头前面1的个数,如果是奇数,那么Second,否则First(奇数说明到Second拿这堆石头);如果全为1,那么奇数个1输出First,否则Second(奇数说明一直交换先后手,然后又回到First)
代码
#include <bits/stdc++.h>
using namespace std;
int const N = 2e5 + 10;
int T, a[N];
int n;
int main() {
cin >> T;
while (T--) {
cin >> n;
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
int k = 1, cnt = 0;
while (a[k] == 1 && k <= n) cnt++, k++;
if (cnt == n) cout << (cnt & 1? "First": "Second") << endl;
else cout << (cnt & 1? "Second": "First") << endl;
}
return 0;
}
C/D. Prefix Flip (Easy Version/Hard Version)
题意: 有T个测试样例,每个测试样例给出一个n,给出2个字符串a和b,问a能否经过2*n次变化变为b。定义每次的变化为:取a的前k个字符,将前k个字符串全部convert(0->1, 1->0),然后将这k个字符串做reverse。如果能的话,输出变化总次数和每次变化的k。(sum_{}n) <= 10^5^
题解: 每次变化可以先比较a[1]和b[i], 然后判断是否相同,如果相同,那么k取1,然后k再取i,这样就能保证a[1]最后等于b[i],那么reverse之后,a[1]放到a[i]的位置,所以每次交换后,a[i] ~ a[n]的位置就已经确定了不需要交换,这样保证只需要2n次变化。但是这样处理的时间复杂度为O(n^2^)。可以利用线段树懒标记的处理方法,每次不做reverse,只是打上标记即可,然后根据标记的特征,相互抵消,具体见代码。
代码:
// flg=0表示正向,没有reverse;flg=1表示反向,已经reverse。
#include<bits/stdc++.h>
using namespace std;
int const N = 1e5 + 10;
int T, n;
char a[N], b[N];
vector<int> ans;
int main()
{
cin >> T;
while(T--) {
cin >> n;
ans.clear();
scanf("%s", a + 1);
scanf("%s", b + 1);
int l = 1, r = n, flg = 0;
for(int i=n;i>=1;i--)
{
if(flg==0)
{
if(a[r]==b[i])
{
r--;
continue;
}
if(a[l]==b[i])
ans.push_back(1);
ans.push_back(i);
l++;
flg=1;
}
else
{
if(a[l]!=b[i])
{
l++;
continue;
}
if(a[r]!=b[i])
ans.push_back(1);
ans.push_back(i);
r--;
flg=0;
}
}
cout << ans.size() << " " ;
for (auto ai: ans) cout << ai << " " ;
cout << endl;
}
return 0;
}