A. 11/22 String

模拟

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
bool solve() {
int n;
string s;
cin >> n >> s;
if (n%2 == 0) return false;
int one = n/2;
string t;
t += string(one, '1');
t += '/';
t += string(one, '2');
return s == t;
}
int main() {
if (solve()) puts("Yes");
else puts("No");
return 0;
}

B. 1122 String

模拟

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
bool solve() {
string s;
cin >> s;
int n = s.size();
if (n&1) return false;
rep(i, n/2) {
if (s[i*2] != s[i*2+1]) return false;
}
set<char> st;
rep(i, n/2) st.insert(s[i*2]);
return st.size() == n/2;
}
int main() {
if (solve()) puts("Yes");
else puts("No");
return 0;
}

C. 11/22 Substring

先对字符串RLE一遍,然后遍历每个 /,然后取左边连续的 1 的个数和右边连续的 2 的个数的最小值,再将它 ×2+1 就可以作为一个备选答案
也可以遍历每个 /,然后从这个位置开始向两边进行扩展

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
string s;
cin >> n >> s;
s = '$'+s+'$';
n = s.size();
int ans = 1;
rep(i, n) if (s[i] == '/') {
int x = 1;
while (s[i-x] == '1' and s[i+x] == '2') x++;
int now = x*2-1;
ans = max(ans, now);
}
cout << ans << '\n';
return 0;
}

D. 1122 Substring

双指针,开一个桶来维护窗口中每种数的出现次数
注意需要分别对奇偶性下标进行讨论

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n);
rep(i, n) cin >> a[i];
int ans = 0;
rep(si, 2) {
vector<int> cnt(n+1);
int r = si;
for (int l = si; l+1 < n; l += 2) {
while (r+1 < n) {
if (a[r] != a[r+1]) break;
if (cnt[a[r]]) break;
cnt[a[r]]++;
r += 2;
}
ans = max(ans, r-l);
if (l == r) r += 2;
else cnt[a[l]]--;
}
}
cout << ans << '\n';
return 0;
}

E. 11/22 Subsequence

可以考虑二分 12 的长度
那么问题就变成了能否取出 11...1/22...2 这样的子序列
可以用vector来维护每种字符的位置,然后二分找到下一个需要的位置即可

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int main() {
int n, q;
string s;
cin >> n >> q >> s;
vector<vector<int>> is(3);
rep(i, n) {
int c = s[i]-'0';
if (s[i] == '/') c = 0;
is[c].push_back(i);
}
const int INF = 1001001001;
auto getNext = [&](int c, int i, int x) {
if (x == 0) return i;
auto& nis = is[c];
int j = lower_bound(nis.begin(), nis.end(), i) - nis.begin();
j += x-1;
if (j < nis.size()) return nis[j]+1;
return INF;
};
rep(qi, q) {
int l, r;
cin >> l >> r;
--l;
auto judge = [&](int k) {
int i = l;
i = getNext(1, i, k);
i = getNext(0, i, 1);
i = getNext(2, i, k);
return i <= r;
};
int ac = -1, wa = n;
while (ac+1 < wa) {
int wj = (ac+wa)/2;
(judge(wj) ? ac : wa) = wj;
}
int ans = 0;
if (ac == -1) ans = 0;
else ans = ac*2+1;
cout << ans << '\n';
}
return 0;
}

F. 1122 Subsequence

状压dp
dp[S] 表示到目前为止已经使用过的数的集合为 S 时贪心地取时下一个位置的最小值

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
inline void chmin(int& a, int b) { if (a > b) a = b; }
int main() {
int n;
cin >> n;
vector<int> a(n);
rep(i, n) cin >> a[i], a[i]--;
int m = 20, m2 = 1<<m;
vector<vector<int>> is(m);
rep(i, n) is[a[i]].push_back(i);
const int INF = 1001001001;
auto getNext = [&](int c, int i, int x) {
if (x == 0) return i;
auto& nis = is[c];
int j = lower_bound(nis.begin(), nis.end(), i) - nis.begin();
j += x-1;
if (j < nis.size()) return nis[j]+1;
return INF;
};
vector<int> dp(m2, INF);
dp[0] = 0;
int ans = 0;
rep(s, m2) {
if (dp[s] != INF) ans = max(ans, popcount(1u*s));
rep(c, m) {
if (s>>c&1) continue;
chmin(dp[s|1<<c], getNext(c, dp[s], 2));
}
}
ans *= 2;
cout << ans << '\n';
return 0;
}

G. Fibonacci Product

数学题