Codeforces Round #804 (Div. 2) 题解
A. The Third Three Number Problem
题意
给你一个整数 \(n\) ,构造满足等式 \((a \bigoplus b)+(b \bigoplus c)+(a \bigoplus c)=n\) 的三个整数 \(a,b,c\) ,或说明这样的整数并不存在。
题目分析
根据样例猜了下如果是奇数则不存在,是偶数的话随便构造下就好。
AC代码
#include <bits/stdc++.h>
#include <limits>
#define IOS \
std::ios::sync_with_stdio(false); \
std::cin.tie(0); \
std::cout.tie(0);
using PII = std::pair<int, int>;
using ll = long long;
void solve()
{
ll n;
std::cin >> n;
if (n % 2 == 1)
std::cout << -1 << '\n';
else
std::cout << n / 2 << ' ' << 0 << ' ' << 0 << '\n';
}
int main()
{
IOS;
int t;
std::cin >> t;
while (t--)
solve();
return 0;
}
B. Almost Ternary Matrix
题意
给一个 \(n\) 行 \(m\) 列的矩阵黑白染色,使得其中每个单元格 \((i,j)\) 的邻格中恰有两个不同色。
题目分析
跟着样例画了画发现按 \({\begin{bmatrix}1&0\\0&1\end{bmatrix}}\) 和 \({\begin{bmatrix}0&1\\1&0\end{bmatrix}}\) 交替染色即可。
AC代码
#include <bits/stdc++.h>
#include <limits>
#define IOS \
std::ios::sync_with_stdio(false); \
std::cin.tie(0); \
std::cout.tie(0);
using PII = std::pair<int, int>;
using ll = long long;
int map[55][55];
void solve()
{
int n, m;
std::cin >> n >> m;
for (int i = 1, f1 = 1; i <= n; i += 2, f1 ^= 1)
{
if (f1 & 1)
{
for (int j = 1, f2 = 1; j <= m; j += 2, f2 ^= 1)
{
if (f2 & 1)
map[i][j] = map[i + 1][j + 1] = 1;
else
map[i][j + 1] = map[i + 1][j] = 1;
}
}
else
{
for (int j = 1, f2 = 1; j <= m; j += 2, f2 ^= 1)
{
if (f2 & 1)
map[i][j + 1] = map[i + 1][j] = 1;
else
map[i][j] = map[i + 1][j + 1] = 1;
}
}
}
for (int i = 1; i <= n; ++i, std::cout << "\n")
for (int j = 1; j <= m; ++j, std::cout << " ")
std::cout << map[i][j];
}
int main()
{
IOS;
int t;
std::cin >> t;
while (t--)
solve();
return 0;
}
C - The Third Problem
题意
定义两个大小为 \(n\) 的排列 \(a,b\) 相似当且仅当:
- 对于所有区间 \([l,r]\) , \(MEX([a_l,a_{l+1}, \cdots ,a_r])=MEX([b_l,b_{l+1}, \cdots ,b_r])\)
现给定排列 \(a\) ,求有多少个与之相似的排列 \(b\) 。
题目分析
首先玩样例,我们发现在 \(b\) 中,相对于 \(a\) ,有些数的位置是恒定不变的;有些数虽然会变,但可变的位置数也不尽相同。考虑 \(MEX\) 的性质,可以发现以下性质:
- 如果 \(a\) 中 \(i\) 在包含 \(0 \sim i-1\) 的最小区间中, 那么 \(b\) 中 \(i\) 也应在包含 \(0 \sim i-1\) 的最小区间中
- 如果 \(a\) 中 \(i\) 在包含 \(0 \sim i-1\) 的最小区间外, 那么 \(b\) 中 \(i\) 的位置理应与 \(a\) 中相同
因此如果 \(i\) 在当前最小区间 \([l,r]\) 内,答案乘上 \((r-l+1)-p\) ,否则扩展当前最小区间。
AC代码
#include <bits/stdc++.h>
#define IOS \
std::ios::sync_with_stdio(false); \
std::cin.tie(0); \
std::cout.tie(0);
using PII = std::pair<int, int>;
using ll = long long;
const int P = 1e9 + 7;
ll solve()
{
int n;
ll ans = 1;
std::cin >> n;
std::vector<int> a(n + 1), pos(n + 1);
for (int i = 1; i <= n; ++i)
{
std::cin >> a[i];
pos[a[i]] = i;
}
int l = std::min(pos[0], pos[1]), r = std::max(pos[0], pos[1]);
for (int p = 2; p < n; ++p)
{
if (pos[p] < l || pos[p] > r)
l > pos[p] ? l = pos[p] : r = pos[p];
else
ans = ans * (r - l - p + 1) % P;
}
return ans;
}
int main()
{
IOS;
int t;
std::cin >> t;
while (t--)
std::cout << solve() << "\n";
return 0;
}
D. Almost Triple Deletions
题意
给你一个长度为 \(n\) 的数组 \(a\) ,你可以执行下列操作任意次:
- 选择一个索引 \(i\) ,如果对该索引有 \(a_i \not = a_{i+1}\) ,则从数组中删除 \(a_i\) 和 \(a_{i+1}\) ,并将数组的剩余部分串联起来
例如,如果 \(a=[1,4,3,3,6,2]\) ,那么在进行 \(i=2\) 的操作后,所得数组将是 \([1,3,6,2]\) 。
要求最后得到的数组中所有元素值相等,求其最大长度。
题目分析
赛时第一眼是DP,捣鼓半天发现不会d又转向贪心,结果贪不出来以为是构造,最后罚坐到结束也没什么好的思路。
首先看下数据范围 \(n \leq 5000\) ,多半是个 \(O(n^2)\) 的算法。我们可以发现当一个长度为 \(n\) 的数组满足下列条件时,它可以被完全删除:
-
\(n\) 是偶数
-
\(a\) 中任意元素的出现次数至多为 \(n/2\)
于是我们可以在 \(O(n^2)\) 的时间内计算出 \(a\) 的每个子数组是否可以被完全删除。
设 \(f[i]\) 表示以 \(a_i\) 结尾的最终数组的最大长度,初始化当 \([1,i-1]\) 可被完全删除时 \(f[i] = 1\) ,否则 \(f[i] = 0\) 。
转移有:
\(f[i] = \max_{j=1}^{i-1}(f[j] + 1).(f[j] > 0 \enspace and \enspace a[i] = a[j] \enspace and \enspace [i+1,j-1] \enspace is \enspace deletable)\)
考虑最终数组中尾部连续的一段 \(a_{j+1},\cdots,a_n\) 也是可能被完全删除的,因此我们需要d到 \(n+1\) ,并且 \(a_{n+1}\) 相当于万能通配符,那么答案即是 \(f[n+1]-1\) (要把 \(a_{n+1}\) 的长度减掉)。
看了下还有dalao用图论的方法做的,只能说我还是太菜了orz
AC代码
#include <bits/stdc++.h>
#define IOS \
std::ios::sync_with_stdio(false); \
std::cin.tie(0); \
std::cout.tie(0);
int solve()
{
int n;
std::cin >> n;
std::vector<int> a(n + 1), cnt(n + 1);
for (int i = 1; i <= n; ++i)
std::cin >> a[i];
std::vector<std::vector<int>> del(n + 1, std::vector<int>(n + 1));
std::vector<int> f(n + 2);
for (int i = 1; i <= n; ++i)
{
std::fill(cnt.begin(), cnt.end(), 0);
for (int j = i, mx = 0; j <= n; ++j)
{
mx = std::max(mx, ++cnt[a[j]]);
if ((j - i + 1) % 2 == 0 && mx <= (j - i + 1) / 2)
del[i][j] = 1;
}
}
for (int i = 1; i <= n + 1; ++i)
f[i] = del[1][i - 1];
f[1] = 1;
for (int i = 1; i <= n + 1; ++i)
for (int j = 1; j <= i - 1; ++j)
if (f[j] && (a[i] == a[j] || i == n + 1) && ((j + 1 > i - 1) || (del[j + 1][i - 1])))
f[i] = std::max(f[i], f[j] + 1);
return f[n + 1] - 1;
}
int main()
{
IOS;
int t;
std::cin >> t;
while (t--)
std::cout << solve() << "\n";
return 0;
}