ARC180 补。
A - ABA and BAB
给定一个长度为 \(n\) 的 AB 串 \(s\),进行任意次操作,求可能的结果个数。
操作:将字串 ABA 改为 A,或 BAB 改为 B。
Solution
愣了我一下。注意到连续的 A 或者 B 都无法进行操作,可以被操作的只有 AB 交替的子串。这种子串只能不断删除 AB,可能结果个数为 \(\lceil \frac{s}{2}\rceil\)。可以将 \(s\) 拆分为若干个 \(t\),这些 \(t\) 是相互独立的,所以直接乘即可。
\(\\\)
Code
// STOOOOOOOOOOOOOOOOOOOOOOOOO hzt CCCCCCCCCCCCCCCCCCCCCCCORZ
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 2.5e5 + 1, kP = 1e9 + 7;
int n;
string s, t;
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n >> s;
LL ans = 1;
char pre = '!';
for (int i = 0; i < n; i++) {
if (s[i] == pre) {
ans = ans * ((t.size() + 1) / 2) % kP;
t.clear();
}
t += s[i], pre = s[i];
}
ans = ans * ((t.size() + 1) / 2) % kP;
cout << ans << '\n';
return 0;
}
B - Improve Inversions
给定一个 \(n\) 排列 \(p\) 和一个正整数 \(k\),求最大操作次数。
操作:交换一个间距至少为 \(k\) 的逆序对。
Solution
对于 \(p\) 作他的逆排列 \(q_{p_i} = i\),题目转为求差至少为 \(k\) 的逆序对。
从左到右一点点吃干抹尽显然不劣。
\(\\\)
Code
// STOOOOOOOOOOOOOOOOOOOOOOOOO hzt CCCCCCCCCCCCCCCCCCCCCCCORZ
#include <algorithm>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 500 + 1;
int n, k;
int p[kN], iv[kN];
vector<PII> ans;
int main() {
cin.tie(0)->sync_with_stdio(0);
cin >> n >> k;
for (int i = 1; i <= n; i++) {
cin >> p[i];
iv[p[i]] = i;
}
for (int i = 2; i <= n; i++) {
for (int j = i - 1; j >= 1; j--) {
if (iv[i] + k <= iv[j]) {
ans.emplace_back(iv[i], iv[j]);
swap(iv[i], iv[j]);
i = j;
}
}
}
cout << ans.size() << '\n';
for (auto [x, y] : ans) {
cout << x << ' ' << y << '\n';
}
return 0;
}
C - Subsequence and Prefix Sum
给定一个长度为 \(n\) 的序列 \(a\),求进行一次操作后可能的结果个数。
操作:选出 \(a\) 的一个子序列并作前缀和。
Solution
不难想到令 \(f_{i, j}\) 表示考虑到 \(i\),子序列总和为 \(j\) 的方案数。
但是直接转移是错误的。问题出在当被转移的 \(j = 0\) 时,你这个点转移不转移都不会改变,但是会改变转移后的 \(j\),不好判。
pharital 说当 \(j = 0\) 的情况可以拉出来单独转移。
令 \(g_i\) 表示 \(i\) 这个数值作子序列结尾,子序列前面的和为 \(0\) 的方案数。于是可以 \(f_{i - 1, 0} \Rightarrow g_{a_i},g_{j} \Rightarrow f_{i, j + a_i}\).
转移 \(f\) 的同时特判转移 \(g\) 即可。
\(\\\)
Code
pharital 提供了一个支持负数下标的安全性未知的神秘写法。
// STOOOOOOOOOOOOOOOOOOOOOOOOO hzt CCCCCCCCCCCCCCCCCCCCCCCORZ
#include <algorithm>
#include <atcoder/modint>
#include <iostream>
#include <numeric>
#include <vector>
using namespace std;
using namespace atcoder;
using mint = modint1000000007;
using LL = long long;
using PII = pair<int, int>;
constexpr int kN = 100 + 1, kS = 1e3 + 1;
int n, a[kN];
mint F[kN][2 * kS], *f[kN], G[2 * kS], *g = G + kS;
int main() {
for (int i = 0; i < kN; i++) {
f[i] = F[i] + kS;
}
cin.tie(0)->sync_with_stdio(0);
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
f[0][0] = 1;
int l = 0, r = 0;
for (int i = 1; i <= n; i++) {
for (int j = l; j <= r; j++) {
f[i][j] += f[i - 1][j];
if (j != 0) {
f[i][j + a[i]] += f[i - 1][j] + g[j];
}
}
g[a[i]] = f[i - 1][0];
l += min(a[i], 0), r += max(a[i], 0);
}
mint ans = 0;
for (int i = l; i <= r; i++) {
ans += f[n][i];
}
cout << ans.val() << '\n';
return 0;
}

浙公网安备 33010602011771号