Codeforces Round 1051 (Div. 2) 补题记录
Codeforces Round 1051 (Div. 2) 补题记录
D - Inversion Graph Coloring
题目大意:
当一个序列 \(b_1, b_2, \dots, b_k\) 存在一种对每个下标 \(i\) 染上红色或蓝色的方式,使得每一对 \(i < j\) 且 \(b_i > b_j\) 的下标 \(i, j\) 的颜色不同时,我们称这个序列是“好”的。
给定一个序列 \(a_1, a_2, \dots, a_n\),计算它“好”的子序列数量,并对 \(10^9 + 7\) 取模。
思路:
考虑什么样的子序列会被计入答案。注意到,当存在下标 \(i < j < k\) 且 \(a_i > a_j > a_k\) 时,不存在合法的染色方案。因此题目可以转化为求最长递减子序列长度小于等于 \(2\) 的子序列个数。
接着我们考虑对于第 \(i\) 个数,会与前面已经组成的哪些子序列形成新的子序列。
-
加入最大值 \(j \leq a_i\) 的子序列中。此时由 \(a_i\) 组成的递减子序列长度为 \(1\)。
-
加入最长递减子序列长度为 \(2\) 且末尾数值 \(k \leq a_i < j\) 的子序列中。此时,\(a_i\) 代替 \(k\) 成为最长递减子序列的最后一个元素,长度依旧为 \(2\)。
根据上面的两种情况以及不选择第 \(i\) 个元素与前面元素构成子序列的情况,我们进行 \(dp\),状态转移如下:
-
不选择 \(a_i\):\(dp[i][j][k] \leftarrow dp[i - 1][j][k];\)
-
\(j \leq a_i\):\(dp[i][a_i][k] \leftarrow dp[i - 1][j][k];\)
-
\(k \leq a_i < j\):\(dp[i][j][a_i] \leftarrow dp[i - 1][j][k].\)
时间复杂度 \(O(n^3)\) 足够通过本题的 Easy Version。
接着我们考虑如何优化 \(dp\)。
注意到在转移时,存在如下关系:
因此可以考虑把第一维砍掉,用树状数组维护 \(dp\) 每行每列的前缀和,求出增量即可。
\(code:\)
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define i64 long long
const int mod = 1000000007;
template <typename T>
struct Fenwick {
int n;
std::vector<T> a;
Fenwick(int n = 0) {
init(n);
}
void init(int n) {
this->n = n;
a.assign(n, T());
}
void add(int x, T v) {
for (int i = x + 1; i <= n; i += i & -i) {
a[i - 1] += v;
}
}
T sum(int x) {
auto ans = T();
for (int i = x; i > 0; i -= i & -i) {
ans += a[i - 1];
}
return ans;
}
T rangeSum(int l, int r) {
return sum(r) - sum(l);
}
};
void MuBai() {
int n;
cin >> n;
vector<int> a(n + 1);
for (int i = 1; i <= n; i ++ ) cin >> a[i];
vector<Fenwick<i64>> row(n + 1), col(n + 1);
for (int i = 0; i <= n; i ++ ) {
row[i].init(n + 1);
col[i].init(n + 1);
}
row[0].add(0, 1), col[0].add(0, 1);
vector f(n + 1, vector<i64>(n + 1, 0));
for (int i = 1; i <= n; i ++ ) {
for (int j = 0; j <= n; j ++ ) {
i64 g = col[j].sum(a[i] + 1) % mod;
i64 h = (a[i] < j) ? (row[j].sum(a[i] + 1) % mod) : 0;
if (g) {
row[a[i]].add(j, g);
col[j].add(a[i], g);
f[a[i]][j] += g;
if (f[a[i]][j] >= mod) f[a[i]][j] -= mod;
}
if (h) {
row[j].add(a[i], h);
col[a[i]].add(j, h);
f[j][a[i]] += h;
if (f[j][a[i]] >= mod) f[j][a[i]] -= mod;
}
}
}
i64 ans = 0;
for (int i = 0; i <= n; i ++ ) {
ans += col[i].sum(n + 1) % mod;
if (ans >= mod) ans -= mod;
}
cout << (ans < mod ? ans : ans - mod) << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int t; cin >> t;
while (t -- ) MuBai();
return 0;
}
E - Make Good
题目大意:
给定一个长度为 \(n\) 的括号字符串 \(s\)。可以进行以下操作无数次:
-
选择一个下标 \(1 \leq i < |s|\),若 \(s[i] = s[i + 1] = '('\),把 \(s[i]\) 和 \(s[i + 1]\) 替换成 \(')'\)。
-
选择一个下标 \(1 \leq i < |s|\),若 \(s[i] = s[i + 1] = ')'\),把 \(s[i]\) 和 \(s[i + 1]\) 替换成 \('('\)。
找出一个可以通过上述操作得到的合法括号序列 \(t\),若不存在则输出 \(-1\)。
思路:
显然,当 \(n\) 为奇数时,一定无解。
接着在没有操作次数限制的情况下,考虑每次操作后不变的性质。注意到,当我们对 \(i\) 进行操作时,奇数位和偶数位上 \('('\) 的数量同时加一或减一。
设 \(odd\) 为奇数位上 \('('\) 的个数,\(even\) 为偶数位上 \('('\) 的个数,可以发现 \(diff = odd - even\) 是恒定的。因此只需要满足 \(diff(s) = diff(t)\) ,\(s\) 和 \(t\) 就是可以互相转换的。
对于一个合法的括号序列 \(ans\),一定有 \(ans[1] = '(', \ ans[n] = ')'\)。设 \(m = \frac{n}{2}\),则奇数位上的 \('('\) 的个数至少为 \(1\),偶数上的 \('('\) 的个数至多为 \(m - 1\),即:\(1 \leq odd \leq m - 1\)。同时,由 \(diff = odd - even = 2 * odd - m\),我们可以推出满足构造答案的条件:
接下来,我们考虑用如下骨架来构造答案,可以证明它总是正确的:
易得,当 \(k\) 为奇数时,\(diff = k - m + 1\),当 \(k\) 为偶数时,\(diff = m - k\)。可以推出:
code:
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define i64 long long
void MuBai() {
int n; string s;
cin >> n >> s;
if (n & 1) {
cout << "-1\n";
return;
}
int odd = 0, even = 0, m = n / 2;
for (int i = 0; i < n; i ++ ) {
if (s[i] == ')') continue;
if (i & 1) even++;
else odd++;
}
int cnt = odd - even;
if (2 - m > cnt || m < cnt || (cnt & 1) != (m & 1)) {
cout << "-1\n";
return;
}
int k = 0;
if (cnt >= 0) k = m - cnt;
else k = cnt + m - 1;
string ans = "";
for (int i = 0; i < k; i ++ ) ans += '(';
for (int i = 0; i < m - k; i ++ ) ans += "()";
for (int i = 0; i < k; i ++ ) ans += ')';
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int t; cin >> t;
while (t -- ) MuBai();
return 0;
}

浙公网安备 33010602011771号