Solution Set【2024.1.7】

CF1919C Grouping Increases

考虑维护出当前的两个子序列,然后贪心的选择将当前元素放入哪个子序列中。

发现决策只与两个子序列的末尾元素和当前元素有关,不妨设两个子序列末尾元素分别为 \(x, y\),并且有 \(x \le y\)

  • \(a_i \le x\),那么无论将 \(a_i\) 放入哪个子序列,均不会产生代价,为了使得后续可以插入的元素范围更大,选择将 \(a_i\) 放入 \(x\) 所在的子序列中。

  • \(y < a_i\),那么无论将 \(a_i\) 放入哪个子序列,均会产生代价,为了使得后续可以插入的元素范围更大,选择将 \(a_i\) 放入 \(y\) 所在的子序列中。

  • \(x \le a_i < y\),那么若将 \(a_i\) 插入 \(x\) 所在的子序列中,会产生代价,而将 \(a_i\) 插入 \(y\) 所在的子序列中不会产生代价。不妨假设我们在插入剩余 \(a_{i + 1}, \cdots, a_n\) 的过程中均采取同一种决策,那么可以发现若插入 \(x\) 所在的子序列中的方案优于插入 \(y\) 所在的子序列中的方案,那么在插入该元素后,两个子序列的末尾元素相同。又因为在这之前插入 \(x\) 所在的子序列中的方案多一点代价,因此无论如何插入 \(y\) 所在的子序列中不劣于插入 \(x\) 所在的子序列中的方案。因此,我们可以在插入 \(a_i\) 时,选择将 \(a_i\) 插入 \(y\) 所在的子序列中。

Code
#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::vector<ValueMatrix> ValueCube;
typedef std::string string;
typedef std::vector<string> StringVector;
typedef std::vector<bool> bitset;
typedef std::vector<bitset> BitMatrix;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::vector<ValuePair> PairVector;
typedef std::vector<PairVector> PairMatrix;
typedef std::tuple<valueType, valueType, valueType> ValueTuple;
typedef std::vector<ValueTuple> TupleVector;
typedef std::vector<TupleVector> TupleMatrix;
typedef std::set<valueType> ValueSet;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    valueType T;

    std::cin >> T;

    for (valueType testcase = 0; testcase < T; ++testcase) {
        valueType N;

        std::cin >> N;

        ValueVector A(N + 1);

        for (valueType i = 1; i <= N; ++i)
            std::cin >> A[i];

        if (N <= 2) {
            std::cout << 0 << '\n';

            continue;
        }

        valueType ans = 0;

        ValueVector L, R;

        L.push_back(N);
        R.push_back(N);

        L.reserve(N);
        R.reserve(N);

        for (valueType i = 1; i <= N; ++i) {
            bool left = A[i] > L.back(), right = A[i] > R.back();

            if (left == right) {
                if (L.back() < R.back()) {
                    ans += L.back() < A[i];

                    L.push_back(A[i]);
                } else {
                    ans += R.back() < A[i];

                    R.push_back(A[i]);
                }
            } else {
                if (!left) {
                    ans += L.back() < A[i];

                    L.push_back(A[i]);
                } else {
                    ans += R.back() < A[i];

                    R.push_back(A[i]);
                }
            }
        }

        std::cout << ans << '\n';
    }

    std::cout << std::flush;

    return 0;
}

CF1919D 01 Tree

考虑深度最大的叶子节点,不难发现其兄弟节点一定是一个深度比其小 \(1\) 的叶子节点,这就意味着他们的 dfs 序是相邻的。

因此我们可以每次选取深度最大的叶子节点,检查其 dfs 序两侧是否存在深度比其小 \(1\) 的叶子节点,若存在则将这两个叶子节点删去,会产生一个新的深度比最大深度小 \(1\) 的叶子节点即其原来的父亲节点,将其插入到 dfs 序列中继续执行删除操作即可。若其 dfs 序两侧不存在深度比其小 \(1\) 的叶子节点,那么我们可以将其删去,那么不存在合法的方案。

具体实现时,可以使用一个堆来维护当前深度最大的叶子节点,使用链表来维护 dfs 序列。

Code
#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::vector<ValueMatrix> ValueCube;
typedef std::string string;
typedef std::vector<string> StringVector;
typedef std::vector<bool> bitset;
typedef std::vector<bitset> BitMatrix;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::vector<ValuePair> PairVector;
typedef std::vector<PairVector> PairMatrix;
typedef std::tuple<valueType, valueType, valueType> ValueTuple;
typedef std::vector<ValueTuple> TupleVector;
typedef std::vector<TupleVector> TupleMatrix;
typedef std::set<valueType> ValueSet;
typedef std::stack<valueType> ValueStack;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    valueType T;

    std::cin >> T;

    for (valueType testcase = 0; testcase < T; ++testcase) {
        valueType N;

        std::cin >> N;

        ValueVector A(N + 1);

        for (valueType i = 1; i <= N; ++i)
            std::cin >> A[i];

        valueType ZeroCount = 0;

        for (valueType i = 1; i <= N; ++i)
            if (A[i] == 0)
                ++ZeroCount;

        if (ZeroCount != 1) {
            std::cout << "No\n";

            continue;
        }

        bool ans = true;
        bitset visited(N + 1, false);
//        ValueVector stack;
        valueType node = 0;

        for (valueType i = 1; i <= N && ans; ++i) {
            valueType x = A[i];

//            if (stack.empty() || stack.back() < x) {
//                stack.push_back(x);
//            } else if (stack.back() > x) {
//                for (valueType j = stack.back(); j > x; --j) {
//                    if (stack.empty() || stack.back() != j) {
//                        ans = false;
//
//                        break;
//                    } else {
//                        stack.pop_back();
//                    }
//                }
//
//                stack.push_back(x);
//            }

            if (x <= node) {
                while (node > x) {
                    if (!visited[node]) {
                        ans = false;

                        break;
                    }

                    --node;
                }
            } else {
                while (node < x) {
                    visited[++node] = false;
                }
            }

            visited[x] = true;
        }

        while (node >= 0 && ans) {
            if (!visited[node]) {
                ans = false;

                break;
            }

            --node;
        }

//        if (stack.empty() || !ans) {
//            std::cout << "No\n";
//
//            continue;
//        }
//
//        for (valueType i = stack.back(); i >= 0 && ans; --i) {
//            if (stack.empty() || stack.back() != i) {
//                ans = false;
//
//                break;
//            } else {
//                stack.pop_back();
//            }
//        }

        if (!ans) {
            std::cout << "No\n";

            continue;
        } else {
            std::cout << "Yes\n";
        }
    }

    std::cout << std::flush;

    return 0;
}

CF1919E Counting Prefixes

考虑枚举序列的和。不妨设序列的和为 \(s\),那么为了满足前缀和最大值的要求,我们可以初始构造出一个形如 \(1, 1, 1, 1, \cdots, 1, 1, 1, -1, -1, \cdots, -1, -1\) 的序列,其中其有 \(p_n\)\(1\)\(p_n - s\)\(-1\)。考虑在此基础上对序列进行修改使得其满足其他前缀和的要求。

\(s_i\) 表示前 \(i\) 个元素的和,那么我们可以发现,若在 \(a_i\) 后插入两个元素 \(-1, 1\),那么 \(s_i\)\(s_i - 1\) 在前缀和集合中均会多出现一次,这启发我们从大到小依次去在序列中插入 \(-1, 1\) 并满足对应的前缀和出现次数的要求。

由于初始序列或为了满足较大的前缀和的要求,当前枚举到的前缀和出现的次数不一定是常数,但是可以通过考虑以上两个因素进行计算。在得到当前前缀和已经出现的次数后,我们便可以得到需要插入的 \(-1, 1\) 的个数,并且每次插入必须插入在当前前缀和出现的位置后。设当前前缀和已经出现了 \(x\) 次,还需要插入 \(y\) 次,那么其方案数为在长度为 \(y\) 的序列中插入 \(x - 1\) 个隔板的方案数,即 \(\dbinom{x + y - 1}{y}\)

这样我们就可以在 \(O(n)\) 的时间内枚举序列的和,然后在 \(O(n)\) 的时间内计算出对应的方案数,总时间复杂度为 \(O(n^2)\)

Code
#include <bits/stdc++.h>

typedef long long valueType;
typedef std::vector<valueType> ValueVector;
typedef std::vector<ValueVector> ValueMatrix;
typedef std::vector<ValueMatrix> ValueCube;
typedef std::string string;
typedef std::vector<string> StringVector;
typedef std::vector<bool> bitset;
typedef std::vector<bitset> BitMatrix;
typedef std::pair<valueType, valueType> ValuePair;
typedef std::vector<ValuePair> PairVector;
typedef std::vector<PairVector> PairMatrix;
typedef std::tuple<valueType, valueType, valueType> ValueTuple;
typedef std::vector<ValueTuple> TupleVector;
typedef std::vector<TupleVector> TupleMatrix;
typedef std::set<valueType> ValueSet;

namespace MODINT_WITH_FIXED_MOD {
    constexpr valueType MOD = 998244353;

    template<typename T1, typename T2, typename T3 = valueType>
    void Inc(T1 &a, T2 b, const T3 &mod = MOD) {
        a = a + b;

        if (a >= mod)
            a -= mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    void Dec(T1 &a, T2 b, const T3 &mod = MOD) {
        a = a - b;

        if (a < 0)
            a += mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 sum(T1 a, T2 b, const T3 &mod = MOD) {
        return a + b >= mod ? a + b - mod : a + b;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 sub(T1 a, T2 b, const T3 &mod = MOD) {
        return a - b < 0 ? a - b + mod : a - b;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 mul(T1 a, T2 b, const T3 &mod = MOD) {
        return (long long) a * b % mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    void Mul(T1 &a, T2 b, const T3 &mod = MOD) {
        a = (long long) a * b % mod;
    }

    template<typename T1, typename T2, typename T3 = valueType>
    T1 pow(T1 a, T2 b, const T3 &mod = MOD) {
        T1 result = 1;

        while (b > 0) {
            if (b & 1)
                Mul(result, a, mod);

            Mul(a, a, mod);
            b = b >> 1;
        }

        return result;
    }
}// namespace MODINT_WITH_FIXED_MOD

using namespace MODINT_WITH_FIXED_MOD;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);

    valueType T;

    std::cin >> T;

    for (valueType testcase = 0; testcase < T; ++testcase) {
        valueType N;

        std::cin >> N;

        valueType const M = 2 * N;

        ValueVector Fact(M + 1, 0), InvFact(M + 1, 0);

        Fact[0] = 1;
        for (valueType i = 1; i <= M; ++i)
            Fact[i] = mul(Fact[i - 1], i);

        InvFact[M] = pow(Fact[M], MOD - 2);
        for (valueType i = M - 1; i >= 0; --i)
            InvFact[i] = mul(InvFact[i + 1], i + 1);

        auto C = [&](valueType n, valueType m) -> valueType {
            if (n < m || n < 0 || m < 0)
                return 0;

            return mul(Fact[n], mul(InvFact[m], InvFact[n - m]));
        };

        ValueVector F(2 * N + 15, 0);

        valueType const offset = N + 5;

        for (valueType i = 0; i < N; ++i) {
            valueType x;

            std::cin >> x;

            ++F[x + offset];
        }

        ++F[offset];

        valueType min = std::numeric_limits<valueType>::max(), max = std::numeric_limits<valueType>::min();

        for (valueType i = 0; i < F.size(); ++i) {
            if (F[i] > 0) {
                min = std::min(min, i);
                max = std::max(max, i);
            }
        }

        if (min == max || std::count(F.begin() + min, F.begin() + max + 1, 0) != 0) {
            std::cout << 0 << '\n';

            continue;
        }

        valueType ans = 0;

        for (valueType s = min; s <= max; ++s) {
            ValueVector G(F.size(), 0);

            G[max - 1] = F[max] + (max > offset) - (max == s);

            for (valueType i = max - 2; i >= min - 1; --i)
                G[i] = F[i + 1] - G[i + 1] + (i >= s) + (i >= offset);

            if (G[min - 1] != 0)
                continue;

            valueType product = 1;

            for (valueType i = min; i < max; ++i)
                Mul(product, C(F[i] - 1, F[i] - G[i]));

            Inc(ans, product);
        }

        std::cout << ans << '\n';
    }

    std::cout << std::flush;

    return 0;
}
posted @ 2024-01-07 21:21  User-Unauthorized  阅读(15)  评论(0编辑  收藏  举报