Codeforces Round #805 (Div. 3) 题解

A. Round Down the Price

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;

void solve()
{
    ll n, d = 0;
    std::cin >> n;
    for (ll m = n; m; m /= 10)
        ++d;
    ll x = (ll)pow(10, d - 1);
    std::cout << n - x << '\n';
}

int main()
{
    IOS;
    int t;
    std::cin >> t;
    while (t--)
        solve();
    return 0;
}

B. Polycarp Writes a String from Memory

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;

ll solve()
{
    ll res = 0;
    std::string s;
    std::cin >> s;
    int p = 0, n = s.length();
    std::vector<int> hash(27);
    while (p < n)
    {
        int cnt = 0;
        while (p < n)
        {
            if (!hash[s[p] - 'a'])
            {
                ++cnt;
                if (cnt > 3)
                    break;
                hash[s[p] - 'a'] = 1;
            }
            ++p;
        }
        ++res;
        std::fill(hash.begin(), hash.end(), 0);
    }
    return res;
}

int main()
{
    IOS;
    int t;
    std::cin >> t;
    while (t--)
        std::cout << solve() << '\n';
    return 0;
}

C. Train and Queries

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;

void solve()
{
    int n, k;
    std::cin >> n >> k;
    std::vector<int> a(n + 1);
    for (int i = 1; i <= n; ++i)
        std::cin >> a[i];
    std::map<int, int> fa, la; // first appear, last appear
    for (int i = 1; i <= n; ++i)
    {
        if (!fa.count(a[i]))
            fa[a[i]] = i;
        la[a[i]] = std::max(fa[a[i]], i);
    }
    for (int i = 1, u, v; i <= k; ++i)
    {
        std::cin >> u >> v;
        if (!fa.count(u) || !fa.count(v))
        {
            std::cout << "No\n";
            continue;
        }
        int st = fa[u], ed = la[v];
        std::cout << (st < ed ? "Yes" : "No") << "\n";
    }
}

int main()
{
    IOS;
    int t;
    std::cin >> t;
    while (t--)
        solve();
    return 0;
}

D. Not a Cheap String

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;

void solve()
{
    std::string s;
    int p;
    std::cin >> s >> p;
    int n = s.length();
    ll now = 0, x;
    std::vector<std::pair<char, int>> a(n + 1);
    for (int i = 1; i <= n; ++i)
    {
        a[i] = {s[i - 1], i};
        now += (s[i - 1] - 'a' + 1);
    }
    std::sort(a.begin() + 1, a.begin() + n + 1);
    std::vector<bool> vis(n + 1);
    for (x = n; x && now > p; --x)
    {
        vis[a[x].second] = true;
        now -= (a[x].first - 'a' + 1);
    }
    std::sort(a.begin() + 1, a.begin() + n + 1, [&](std::pair<char, int> lft, std::pair<char, int> rht)
              { return lft.second < rht.second; });
    std::string ans;
    for (int i = 1; i <= n; ++i)
        if (!vis[i])
            ans.push_back(a[i].first);
    std::cout << ans << std::endl;
}

int main()
{
    IOS;
    int t;
    std::cin >> t;
    while (t--)
        solve();
    return 0;
}

E. Split Into Two Sets

题意

现有 \(n\) 张牌,每张包含 \(1 \sim n\) 的两个整数 \(a_i,b_i\) ,问能否将这 \(n\) 张牌分成两组,使每组中牌上的数均不相同。

题目分析

首先排除以下两种情况:

  • 某张牌上的数字相同(即 \(a_i = b_i\)
  • 存在两张以上的牌包含数 \(x\)

假设现在牌 \(i\)\(j\) 包含数 \(x\) ,我们不妨在点 \(i\) 和点 \(j\) 之间连一条边,然后进行二分图染色判定即可。

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;

void solve()
{
    int n, isok = 1;
    std::cin >> n;
    std::vector<int> a(n + 1), b(n + 1);
    std::vector<std::vector<int>> e(n + 1), g(n + 1);
    for (int i = 1; i <= n; ++i)
    {
        std::cin >> a[i] >> b[i];
        if (a[i] == b[i])
            isok = 0;
        e[a[i]].push_back(i);
        e[b[i]].push_back(i);
    }
    for (int i = 1; i <= n; ++i)
    {
        if (e[i].size() > 2)
        {
            isok = 0;
            break;
        }
        if (e[i].size() == 2)
        {
            g[e[i][0]].push_back(e[i][1]);
            g[e[i][1]].push_back(e[i][0]);
        }
    }
    std::vector<int> v(n + 1, -1);
    std::function<void(int, int)> dfs = [&](int x, int col)
    {
        v[x] = col;
        for (auto y : g[x])
        {
            if (v[y] == -1)
                dfs(y, col ^ 1);
            else if (v[y] == col)
                isok = 0;
        }
    };
    for (int i = 1; i <= n; ++i)
        if (v[i] == -1)
            dfs(i, 1);
    std::cout << (isok ? "YES\n" : "NO\n");
}

int main()
{
    IOS;
    int t;
    std::cin >> t;
    while (t--)
        solve();
    return 0;
}

F. Equate Multisets

题意

给你两个大小相等的 multiset \(a\)\(b\) ,每次操作可以把 \(b\) 中的一个元素乘 \(2\) 或除以 \(2\) 。问能否经过若干次操作,使得 \(a\)\(b\) 相等。

题目分析

偶因子是没用的,所以可以先全部干掉,然后记下 \(a\) 中各元素剩余的最大奇因子。之后遍历 \(b\) ,如果 \(b_i\)\(a\) 中有与之匹配的项,就将对应的奇因子数减 1 。否则就不断将 \(b_i\) 除以 2 直到其在 \(a\) 中出现为止。如果 \(b_i\) 除到 0 都未能匹配,则说明 \(a\)\(b\) 不可能相等。

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;

bool solve()
{
    int n;
    std::cin >> n;
    std::vector<int> a(n + 1), b(n + 1);
    std::map<int, int> mp;
    for (int i = 1; i <= n; ++i)
    {
        std::cin >> a[i];
        while (!(a[i] & 1))
            a[i] >>= 1;
        ++mp[a[i]];
    }
    for (int i = 1; i <= n; ++i)
        std::cin >> b[i];
    for (int i = 1; i <= n; ++i)
    {
        while (b[i] && !mp[b[i]])
            b[i] >>= 1;
        if (b[i] == 0)
            return false;
        --mp[b[i]];
    }
    return true;
}

int main()
{
    IOS;
    int t;
    std::cin >> t;
    while (t--)
        std::cout << (solve() ? "YES" : "NO") << std::endl;
    return 0;
}

G1. Passable Paths (easy version)

题意

定义一个点集为可连通的,当且仅当树上存在某条路径穿过这组顶点,而不经过任何一条边两次(这条路径可以访问该点集外的其它顶点)。

现有 \(q\) 次询问。每次询问某个点集是否为可连通的。

题目分析

观察到简单版本的 \(q\) 很小,先预处理出每个点的父节点与深度, 对每个询问将点集放优先队列中按深度排序,然后不断往上爬,同时记录父节点的子节点数,如果父节点不在队列中就入队。如果最后的根节点的子节点数 \(> 2\) 或是其它节点的子节点数 \(\geq 2\) 则说明不连通,否则连通。

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;

int main()
{
    IOS;
    int n;
    std::cin >> n;
    std::vector<std::vector<int>> g(n + 1);
    std::vector<int> dep(n + 1), pa(n + 1);
    for (int i = 1, u, v; i < n; ++i)
    {
        std::cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    std::function<void(int, int)> getDepth = [&](int u, int fa)
    {
        pa[u] = fa, dep[u] = dep[fa] + 1;
        for (auto v : g[u])
            if (v != fa)
                getDepth(v, u);
    };
    auto solve = [&]()
    {
        int k;
        std::cin >> k;
        std::vector<int> inq(n + 1), son(n + 1);
        std::priority_queue<PII, std::vector<PII>> q;
        for (int i = 1, x; i <= k; ++i)
        {
            std::cin >> x;
            inq[x] = 1;
            q.push({dep[x], x});
        }
        while (q.size() > 1)
        {
            PII t = q.top();
            q.pop();
            int u = t.second, d = t.first;
            if (son[u] > 1)
                return false;
            int fa = pa[u];
            son[fa] += 1;
            if (inq[fa])
                continue;
            inq[fa] = true;
            q.push({dep[fa], fa});
        }
        PII t = q.top();
        q.pop();
        int u = t.second, d = t.first;
        if (son[u] <= 2)
            return true;
        return false;
    };
    getDepth(1, 0);
    int q;
    std::cin >> q;
    while (q--)
        std::cout << (solve() ? "YES\n" : "NO\n");
    return 0;
}

G2. Passable Paths (hard version)

题目分析

首先将点集按深度排序,找出点集中距离最远的两点,称之为起点 $s $ 与终点 \(t\) 。对于点集中的任意一点 \(p_i\)\(lca(s,p_i)\)\(lca(t,p_i)\) 二者中必然有一者等于 \(p_i\) ,另一者等于 \(lca(s,t)\) ,依此判定整个点集即可。复杂度 \(O(nlog^2n)\)

AC代码

#include <bits/stdc++.h>
#define IOS                           \
    std::ios::sync_with_stdio(false); \
    std::cin.tie(0);                  \
    std::cout.tie(0);
#define PLL std::pair<ll, ll>
using ll = long long;
const ll inf = 1e18;

struct HLD
{
    int N;
    std::vector<std::vector<int>> &G;
    std::vector<int> fa, siz, dep, son, top;
    HLD(std::vector<std::vector<int>> &G, int root = 0) : N(G.size()), G(G), fa(N, 0), siz(N, 0), dep(N, 0), son(N, 0), top(N, 0)
    {
        dfs1(root, 0);
        dfs2(root, root);
    };
    void dfs1(int u, int f)
    {
        siz[u] = 1, fa[u] = f, dep[u] = dep[f] + 1;
        for (auto v : G[u])
            if (v != f)
            {
                dfs1(v, u);
                siz[u] += siz[v];
                if (siz[v] > siz[son[u]])
                    son[u] = v;
            }
    }
    void dfs2(int u, int t)
    {
        top[u] = t;
        if (son[u])
            dfs2(son[u], t);
        for (auto v : G[u])
            if (v != fa[u] && v != son[u])
                dfs2(v, v);
    }
    int lca(int x, int y)
    {
        while (top[x] ^ top[y])
        {
            if (dep[top[x]] < dep[top[y]])
                std::swap(x, y);
            x = fa[top[x]];
        }
        if (dep[x] > dep[y])
            std::swap(x, y);
        return x;
    }
};

int main()
{
    IOS;
    int n, q;
    std::cin >> n;
    std::vector<std::vector<int>> g(n + 1);
    for (int i = 1, u, v; i < n; ++i)
    {
        std::cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }
    HLD hld(g, 1);
    std::cin >> q;
    for (int i = 1, k; i <= q; ++i)
    {
        std::cin >> k;
        std::vector<int> p(k + 1);
        for (int j = 1; j <= k; ++j)
            std::cin >> p[j];
        std::sort(p.begin() + 1, p.begin() + k + 1, [&](int x, int y)
                  { return hld.dep[x] > hld.dep[y]; });
        int s = p[1], t = p[1], mx = 0; // start point is the deepest point
        for (int j = 2; j <= k; ++j)
        {
            int dis = hld.dep[s] + hld.dep[p[j]] - 2 * hld.dep[hld.lca(s, p[j])];
            if (dis > mx)
                t = p[j], mx = dis;
        }
        int lca = hld.lca(s, t), flag = 1;
        for (int j = 1; j <= k; ++j)
        {
            if (p[j] == s || p[j] == t)
                continue;
            int p1 = hld.lca(s, p[j]), p2 = hld.lca(p[j], t);
            if ((p1 == p[j] && p2 == lca) || (p1 == lca && p2 == p[j]))
                continue;
            flag = 0;
            break;
        }
        std::cout << (flag ? "YES" : "NO") << std::endl;
    }
    return 0;
}
posted @ 2022-07-11 01:57  FoXreign  阅读(85)  评论(0编辑  收藏  举报