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;
}
posted @ 2022-07-05 23:56  FoXreign  阅读(24)  评论(0编辑  收藏  举报