题目 | A | B | C1 | C2 | D | E |
---|---|---|---|---|---|---|
√ | √ | √ | √ | √ |
rank 503/24068
A - Common Subsequence
需要求的是最短公共子序列,一开始没反应过来卡了一会。
只有两种情况:两个串有相同字符和没有相同字符。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int b[1005];
bool have[1005];
int main() {
int t = 0;
cin >> t;
while (t--) {
int n, m;
cin >> n >> m;
for (int i = 0; i < 1005; ++i) {
have[i] = false;
}
for (int i = 0; i < n; ++i) {
scanf("%d", a + i);
have[a[i]] = true;
}
for (int j = 0; j < m; ++j) {
scanf("%d", b + j);
}
bool ok = false;
for (int i = 0; i < m; ++i) {
if(have[b[i]]) {
if(!ok)cout<<"YES"<<endl;
cout<<1<<' '<<b[i]<<endl;
ok = true;
break;
}
}
if(!ok)cout<<"NO"<<endl;
}
}
B - Sequential Nim
从后向前推可以找到必胜者。
当前值为1 -> 必胜者对换
当前值不为1 -> 第一个取该值的人胜利
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int a[100005];
int main() {
int t = 0;
cin >> t;
while (t--) {
int n, m;
cin >> n ;
int win = 0;
for (int i = 0; i < n; ++i) {
scanf("%d", a + i);
}
bool nxtwin = false;
for (int j = n - 1; j >= 0; --j) {
if(j == n - 1) {
win = 1;
nxtwin = true;
}
else if(a[j] > 1) {
if(!nxtwin){
nxtwin = true;
win++;
}
}
else {
win ++;
nxtwin = !nxtwin;
}
}
if(win&1)cout<<"First\n";
else cout<<"Second\n";
}
}
C1 - Prefix Flip (Easy Version)
C2 - Prefix Flip (Hard Version)
对第一个进行翻转取反、前n个进行翻转取反,可以使a的第n个字符与b相同,从后向前进行操作,最多进行2n步。
每次操作时需要维护当前a串第一个字符在原a串中的位置和取反次数。
复杂度O(n)。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
string a, b;
int ai, aj;
bool rev;//剩余序列是否正序
bool xx;//是否翻转
void flip(int p){
if(rev) aj--;
else ai++;
rev = !rev;
xx = !xx;
}
char get(){
int c = (rev? a[aj] : a[ai]) - '0';
if(xx) c = !c;
return '0' + c;
}
int main() {
int t = 0;
cin >> t;
while (t--) {
int n;
cin>>n;
cin>>a>>b;
ai = 0;
aj = n - 1;
rev = false;
xx = true;
vector<int> ans;
for (int i = n - 1; i >= 0; i--) {
if(get() != b[i]) ans.push_back(1);
ans.push_back(i+1);
flip(n-1);
}
cout<<ans.size()<<' ';
for (int j : ans) {
cout<<j<<' ';
}
cout<<endl;
}
}
D - Unmerge
可以发现对于合并后的连续递减序列,必在合并前的同一个序列中。
因此可以将合并后的序列划分为一些连续递减片段,判断使用这些片段是否可以填满容量为n的背包。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int main() {
int t = 0;
cin >> t;
while (t--) {
int n;
int p[2005*2];
cin>>n;
for (int i = 0; i < 2 * n; ++i) {
scanf("%d", p+i);
}
vector<int> pieces = {};
for (int i = 0; i < 2*n;) {
int j = i + 1;
while(j < 2 * n && p[i] > p[j]){
j++;
}
pieces.push_back(j - i);
i = j;
}
int dp[2005][2] = {};
bool tt = 0;
for (int p : pieces) {
for (int i = 1; i <= n; ++i) {
if(i < p)dp[i][tt] = dp[i][!tt];
else dp[i][tt] = max(dp[i-p][!tt] + p, dp[i][!tt]);
}
tt = !tt;
}
cout<<(dp[n][tt] == n? "YES":"NO")<<endl;
}
}