题解 | 牛客周赛 Round 142

A 小苯的ovo3.0

知识点:字符串、大小写转换

把输入字符串统一转成小写后,判断是否等于 $\texttt{ovo}$ 即可。

时间复杂度 $\mathcal{O}(1)$。

void solve() {
    string s, tar = "ovo";
    cin >> s;
    auto tolow = [&](char c) -> char {
        if ('A' <= c && c <= 'Z') return c + 32;
        return c;
    };
    for (int i = 0; i < 3; ++i) {
        if (tolow(s[i]) != tar[i]) {
            cout << "NO" << endl;
            return;
        }
    }
    cout << "YES" << endl;
}

B 小苯的双端队列

知识点:双端队列、模拟

初始双端队列为 $1,2,\dots,n$。如果数组 $a$ 可以作为出队序列,那么每一步要取出的 $a_i$ 必须等于当前队首或队尾。

因此直接模拟:若 $a_i$ 等于队首则弹队首,等于队尾则弹队尾,否则无解。

时间复杂度 $\mathcal{O}(n)$。

void solve() {
    int n;
    cin >> n;
    deque<int> b(n);
    iota(all(b), 1);
    vector<int> a(n);
    for (int i = 0; i < n; ++i) cin >> a[i];
    for (int i = 0; i < n; ++i) {
        if (b.front() == a[i])
            b.pof();
        else if (b.back() == a[i])
            b.pob();
        else {
            cout << "NO" << endl;
            return;
        }
    }
    cout << "YES" << endl;
}

C 小苯的整除序列

知识点:贪心、子序列

设当前已经选出了长度为 $ans$ 的合法子序列,那么下一个要选的数必须满足能被 $ans+1$ 整除。

从左到右扫描数组,遇到第一个满足 $a_i \bmod (ans+1)=0$ 的数就选它。这样做一定不劣,因为越早选中当前位置,留给后续选择的元素越多。

时间复杂度 $\mathcal{O}(n)$。

void solve() {
    int n, ans = 0;
    cin >> n;
    for (int i = 0, x; i < n; ++i) {
        cin >> x;
        if (x % (ans + 1) == 0) ans++;
    }
    cout << ans << endl;
}

D 小苯的幼儿园

知识点:前缀和、环形差分、构造判定

设最终每个人都有 $k$ 颗糖,则必须满足 $\sum a_i$ 能被 $n$ 整除,且 $k=\frac{\sum a_i}{n}$。

记每个人相对目标值的差为 $a_i-k$,沿环做前缀和 $s$。一次给糖相当于让相邻位置之间产生 $0/1$ 的流量差,因此所有前缀和只允许落在两个相邻的值之间。

所以只需判断前缀和最大值与最小值之差是否不超过 $1$。

时间复杂度 $\mathcal{O}(n)$。

void solve() {
    int n, sum = 0;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) cin >> a[i], sum += a[i];
    if (sum % n) {
        cout << "NO" << endl;
        return;
    }
    int k = sum / n, s = 0, mx = 0, mn = INF;
    for (auto v : a) s += v - k, mx = max(mx, s), mn = min(mn, s);
    cout << (mx - mn <= 1 ? "YES" : "NO") << endl;
}

E 小苯的区间操作

知识点:构造判定、局部极值

一次操作只能选择两端相等且中间不小于端点的区间整体减一,本质上可以削掉“谷底上的一层”。

如果存在严格峰值,即某个位置比左右相邻都大,那么它无法通过合法区间被单独削平,因此无解。边界同理,若 $a_1>a_2$ 或 $a_n>a_{n-1}$ 也无解。

反之,若不存在这样的峰值,序列可以按高度从低到高逐层消去,最终变成全 $0$。

时间复杂度 $\mathcal{O}(n)$。

void solve() {
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; ++i) cin >> a[i];
    if (n == 1) {
        cout << (a[0] == 0 ? "Yes" : "No") << endl;
        return;
    }
    bool f = (a[0] > a[1]) | (a[n - 1] > a[n - 2]);
    for (int i = 1; i < n - 1; ++i) f |= (a[i] > a[i - 1] && a[i] > a[i + 1]);
    cout << (f ? "No" : "Yes") << endl;
}

F 小苯的DFS

知识点:树形 DFS、区间排序、概率计数

对每棵子树,记录其中权值的最小值和最大值。若 DFS 序列要单调不降,则对于任意节点 $u$:

首先必须有子树内所有点权都不小于 $a_u$,否则访问完 $u$ 后进入子树时一定下降。

其次,$u$ 的若干子树之间必须能排成一个顺序,使得前一棵子树的最大值不超过后一棵子树的最小值。把每棵子树看成区间 $[mn,mx]$,按 $mn$ 排序后检查相邻区间是否满足 $mx_i\le mn_{i+1}$。

若可行,合法访问顺序只来自完全相同区间之间的任意排列。若当前节点有 $k$ 个子节点,其中相同区间分组大小为 $c_1,c_2,\dots$,则当前节点贡献概率为:

$$\frac{\prod c_i!}{k!}$$

所有节点贡献相乘即为答案。

时间复杂度 $\mathcal{O}(n\log n)$。

void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; ++i) cin >> a[i];
    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);
    }
    Z ans = 1;
    auto dfs = [&](auto &&self, int u, int fa) -> PII {
        int mn = a[u], mx = a[u];
        vector<PII> child;

        for (auto v : g[u]) {
            if (v == fa) continue;
            auto [vmn, vmx] = self(self, v, u);

            if (ans == 0) return {0, 0};

            child.pb({vmn, vmx});
            cmin(mn, vmn);
            cmax(mx, vmx);
        }

        if (mn < a[u]) {
            ans = 0;
            return {0, 0};
        }

        if (child.size()) {
            sort(child);

            int k = child.size();

            for (int i = 0; i < k - 1; i++) {
                if (child[i].se > child[i + 1].fi) {
                    ans = 0;
                    return {0, 0};
                }
            }

            Z ways = 1;
            int cnt = 1;
            for (int i = 1; i < k; i++) {
                if (child[i] == child[i - 1]) {
                    cnt++;
                } else {
                    ways *= C.fac(cnt);
                    cnt = 1;
                }
            }

            ans *= ways * C.fac(cnt) / C.fac(k);
        }

        return {mn, mx};
    };
    dfs(dfs, 1, 0);
    cout << ans << endl;
}
暂无评论

发送评论 编辑评论


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