题解 | 牛客周赛 Round 136

A 小红的数组重排

题目保证三个元素互不相同,直接位移一位即可。

void solve() {
    int a, b, c;
    cin >> a >> b >> c;
    cout << c << " " << a << " " << b << endl;
}

B 小红的回文串构造

显然的,除了长度为 $1$ 的回文串,其他回文串必然有相同字符。

void solve() {
    int n;
    cin >> n;
    if (n == 1)
        cout << 'a' << endl;
    else
        cout << "No" << endl;
}

C 小红的排列

最终一定是奇数有 $A=\lceil\frac{n}{2}\rceil$ 个,偶数有 $B=\lfloor\frac{n}{2}\rfloor$ 个,边界条件就是:必须是奇数的数量大于 $A$ ,或者必须是偶数的数量大于 $B$ 。

记有 $x$ 个 $?$ ,$b$ 个偶数,最后的方案数即为
$$
{\text{x个?中选出}B-b\text{个分给偶数的方案数}}\times{\text{奇数全排列}}\times{{\text{偶数全排列}}}\
ans = \binom{x}{\frac{n}{2}-b}\times A!\times B!
$$

void solve() {
    int n;
    string s;
    cin >> n >> s;
    Z ans = 1;
    int a = 0, b = 0, x = 0;
    for (auto v : s) {
        a += v == 'j';
        b += v == 'o';
        x += v == '?';
    }
    if (b > n / 2 || a > (n + 1) / 2) {
        cout << 0 << endl;
        return;
    }
    cout << C.C(x, n / 2 - b) * C.fac(n / 2) * C.fac((n + 1) / 2) << endl;
}

D 小红的中位数

排序后,记中位数为 $x$ ,数组为 ${a_1,a_2,…,x,x,x,…,a_{n-1},a_n}$ ,记录中位数左边和右边的数字个数 $L$ 和 $R$​ 。

若新中位数要小于 $x$ ,那么剩余数组里至少有一半以上的位置要被小于 $x$ 的数占住,因此剩余长度不能超过 $2L$ 。

若新中位数要大于 $x$ ,那么剩余数组里必须有足够多的大于 $x$ 的数把中位数顶过去,因此剩余长度不能超过 $2R-1$。

直接计算即可。

void solve() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) cin >> a[i];
    sort(all(a));
    int L = lower_bound(all(a), a[(n - 1) / 2]) - a.begin();
    int R = a.end() - upper_bound(all(a), a[(n - 1) / 2]);

    if (L == 0 && R == 0) {
        cout << -1 << endl;
        return;
    }

    int ans = n + 1;
    if (L > 0) ans = min(ans, n - 2 * L);
    if (R > 0) ans = min(ans, n - (2 * R - 1));

    cout << ans << endl;
}

E 小红的树上博弈

我们用 $f(x)$ 记录小红走到这个点能否保证一定胜利。

叶子节点一定是 $f(x) = true$,因为小红一旦走到叶子就立刻获胜。

对于非根节点 $u$ ,如果它的孩子里,至少有 $2$ 个是 $f(x)=true$ ,那么小红必胜。因为紫方每回合只能封掉 $u$ 的一个相邻红点,红方总能选另一个仍然能继续获胜的孩子。

对于根节点 $1$ ,因为一开始红方先走、紫方还没来得及封点,所以根节点只要有至少 $1$ 个 $f(x)=true$​​​ 的孩子,红方就能赢。

递归版:

void solve() {
    int n;
    cin >> n;
    vector<vector<int>> g(n + 1);
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        g[u].pb(v), g[v].pb(u);
    }
    vector<bool> f(n + 1);
    auto dfs = [&](auto &&self, int u, int fa) -> void {
        int cnt = 0;
        bool ok = 1;
        for (auto v : g[u]) {
            if (v == fa) continue;
            ok = 0;
            self(self, v, u);
            cnt += f[v];
        }
        if (ok)
            f[u] = 1;
        else if (u == 1)
            f[u] = cnt >= 1;
        else
            f[u] = cnt >= 2;
    };
    dfs(dfs, 1, 0);
    cout << (f[1] ? "red" : "purple") << endl;
}

部分题目可能会出现递归过深导致爆栈的问题,在懒得开大占空间的情况下,我更推荐您提前练习将此类题目写成显式的版本。

void solve() {
    int n;
    cin >> n;
    vector<vector<int>> g(n + 1);
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        g[u].pb(v), g[v].pb(u);
    }
    vector<int> pa(n + 1), order, st;
    st.pb(1);
    pa[1] = 0;
    while (!st.empty()) {
        auto u = st.back();
        st.pob();
        order.pb(u);
        for (auto v : g[u]) {
            if (v == pa[u]) continue;
            pa[v] = u;
            st.pb(v);
        }
    }

    vector<bool> f(n + 1);

    for (int i = n - 1; i >= 0; --i) {
        int u = order[i], cnt = 0;
        for (auto v : g[u]) {
            if (pa[v] == u && f[v]) cnt++;
        }

        bool ok = true;
        for (auto v : g[u]) {
            if (pa[v] == u) {
                ok = false;
                break;
            }
        }

        if (ok)
            f[u] = 1;
        else if (u == 1)
            f[u] = cnt >= 1;
        else
            f[u] = cnt >= 2;
    }

    cout << (f[1] ? "red" : "purple") << endl;
}

F 小红的点构造

先计算出所有 $n$ 个点最多能构造多少对相邻点,然后找在这样的构造方案下, $k$ 组相邻需要多少个点,剩余的边用一条链接在初始点上,多余的点隔一格放在角落即可。

void solve() {
    int n, k;
    cin >> n >> k;
    vector<PII> P;
    vector<ll> E;
    P.pb({0, 0});
    E.pb(0);
    int d = 1;
    while (P.size() < n) {
        for (int x = 0; x < d && P.size() < n; ++x) {
            P.pb({x, d});
            E.pb(E.back() + (x == 0 ? 1 : 2));
        }
        for (int y = 0; y < d && P.size() < n; ++y) {
            P.pb({d, y});
            E.pb(E.back() + (y == 0 ? 1 : 2));
        }
        if (P.size() < n) {
            P.pb({d, d});
            E.pb(E.back() + 2);
        }
        d++;
    }
    if (E.back() < k) {
        cout << "No" << endl;
        return;
    }
    cout << "Yes" << endl;
    int pos = 0;
    for (int i = 0; i < n; ++i) {
        if (E[i] <= k) {
            pos = i + 1;
        }
    }
    for (int i = 0; i < pos; ++i) {
        cout << P[i].fi << " " << P[i].se << endl;
    }
    int r = k - E[pos - 1], rem = n - pos, ptr = -1;
    if (rem) {
        if (r == 1) {
            int mx = -1, yy = -1;
            for (int i = 0; i < pos; ++i) {
                if (P[i].fi > mx) {
                    mx = P[i].fi;
                    yy = P[i].se;
                }
            }
            cout << mx + 1 << " " << yy << endl;
            rem--;
        }
        int x = -1e8, y = -1e8;
        while (rem > 0) {
            cout << x << " " << y << endl;
            x += 2;
            rem--;
        }
    }
}

头文件

#include <bits/stdc++.h>
#define pb push_back
#define pf push_front
#define pob pop_back
#define pof pop_front
#define eb emplace_back
#define fi first
#define se second
#define all(a) a.begin(), a.end()
#define rall(a) a.rbegin(), a.rend()
#define endl "\n"
using namespace std;

using ll = long long;
using ld = long double;
using ui = unsigned;
using ull = unsigned long long;
using i128 = __int128;
using PII = pair<int, int>;
using PLL = pair<ll, ll>;
using TIII = tuple<int, int, int>;
using TLLL = tuple<ll, ll, ll>;

void init() {
}

void solve() {
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);

    init();

    int t = 1;
    cin >> t;
    cout << fixed << setprecision(15);
    for (int _ = 1; _ <= t; ++_) {
        solve();
    }

    return 0;
}

自动取模

constexpr int MOD = 998244353;

template <class T>
constexpr T ksm(T a, ll b) {
    T res = 1;
    while (b) {
        if (b & 1)
            res *= a;
        b >>= 1;
        a *= a;
    }
    return res;
}

template <int P>
struct MInt {
    int x;
    constexpr MInt() : x() {}
    constexpr MInt(ll x) : x{norm(x % getMod())} {}
    static int Mod;
    constexpr static int getMod() {
        if (P > 0) {
            return P;
        } else {
            return Mod;
        }
    }
    constexpr static void setMod(int Mod_) {
        Mod = Mod_;
    }
    constexpr int norm(int x) const {
        if (x < 0) {
            x += getMod();
        }
        if (x >= getMod()) {
            x -= getMod();
        }
        return x;
    }
    constexpr int val() const {
        return x;
    }
    explicit constexpr operator int() const {
        return x;
    }
    constexpr MInt operator-() const {
        MInt res;
        res.x = norm(getMod() - x);
        return res;
    }
    constexpr MInt inv() const {
        assert(x != 0);
        return ksm(*this, getMod() - 2);
    }
    constexpr MInt &operator*=(MInt rhs) & {
        x = 1LL * x * rhs.x % getMod();
        return *this;
    }
    constexpr MInt &operator+=(MInt rhs) & {
        x = norm(x + rhs.x);
        return *this;
    }
    constexpr MInt &operator-=(MInt rhs) & {
        x = norm(x - rhs.x);
        return *this;
    }
    constexpr MInt &operator/=(MInt rhs) & {
        return *this *= rhs.inv();
    }
    friend constexpr MInt operator*(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res *= rhs;
        return res;
    }
    friend constexpr MInt operator+(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res += rhs;
        return res;
    }
    friend constexpr MInt operator-(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res -= rhs;
        return res;
    }
    friend constexpr MInt operator/(MInt lhs, MInt rhs) {
        MInt res = lhs;
        res /= rhs;
        return res;
    }
    friend constexpr istream &operator>>(istream &is, MInt &a) {
        ll v;
        is >> v;
        a = MInt(v);
        return is;
    }
    friend constexpr ostream &operator<<(ostream &os, const MInt &a) {
        return os << a.val();
    }
    friend constexpr bool operator==(MInt lhs, MInt rhs) {
        return lhs.val() == rhs.val();
    }
    friend constexpr bool operator!=(MInt lhs, MInt rhs) {
        return lhs.val() != rhs.val();
    }
};

template <>
int MInt<0>::Mod = 998244353;

template <int V, int P>
constexpr MInt<P> CInv = MInt<P>(V).inv();

using Z = MInt<MOD>;

组合数学

struct Comb {
    int n;
    vector<Z> _fac, _inv;

    Comb() : n(0), _fac{1}, _inv{0} {}
    Comb(int n) : Comb() {
        init(n);
    }
    void init(int m) {
        if (m <= n)
            return;
        _fac.resize(m + 1);
        _inv.resize(m + 1);
        for (int i = n + 1; i <= m; i++) {
            _fac[i] = _fac[i - 1] * i;
        }
        _inv[m] = _fac[m].inv();
        for (int i = m; i > n; i--) {
            _inv[i - 1] = _inv[i] * i;
        }
        n = m;
    }
    Z fac(int x) {
        if (x > n)
            init(x);
        return _fac[x];
    }
    Z inv(int x) {
        if (x > n)
            init(x);
        return _inv[x];
    }
    Z C(int x, int y) {
        if (x < 0 || y < 0 || x < y)
            return 0;
        return fac(x) * inv(y) * inv(x - y);
    }
    Z A(int x, int y) {
        if (x < 0 || y < 0 || x < y)
            return 0;
        return fac(x) * inv(x - y);
    }
};
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇