牛客小白月赛124

链接:https://ac.nowcoder.com/acm/contest/123787

A – 小红的点构造

算法:

    构造,贪心。

思路:

    无。

关键代码:

void miyan()
{
    int x, y;
    cin >> x >> y;

    cout << x + 1 << ' ' << y + 1 << endl;
}

B – 小红的数组重排

算法:

    构造,贪心。

思路:

    无。

关键代码:

void miyan()
{
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; ++i)
        cin >> a[i];

    ranges::sort(a, greater<int>());

    for (auto x : a)
        cout << x << ' ';
    cout << endl;
}

C – 小红下象棋

算法:

    模拟。

思路:

    无。

关键代码:

void miyan()
{
    int x, y, n;
    cin >> x >> y >> n;
    vector<pii> a(n);
    for (int i = 0; i < n; ++i)
        cin >> a[i].first >> a[i].second;

    int dx[8] = {-2, -2, -1, -1, 1, 1, 2, 2};
    int dy[8] = {-1, 1, -2, 2, -2, 2, -1, 1};

    set<pii> s;
    for (int i = 0; i < n; ++i)
    {
        auto [xx, yy] = a[i];
        for (int j = 0; j < 8; ++j)
        {
            int a = xx + dx[j], b = yy + dy[j];

            s.insert({a, b});
        }
    }

    if (s.count({x, y}))
    {
        cout << "B" << endl;
        return;
    }

    int cnt = 0;
    for (int i = -1; i <= 1; ++i)
    {
        for (int j = -1; j <= 1; ++j)
        {
            if (!i && !j)
                continue;

            if (s.count({x + i, y + j}))
                ++cnt;
        }
    }

    if (cnt == 8)
        cout << "A" << endl;
    else
        cout << "C" << endl;
}

D – 小红的区间查询

算法:

    数论。

思路:

    要求找满足以下等式的 \(x\) 的数量:

    \(x – a \equiv 0 \pmod{x – b}\)

    消除等式前面变量 \(x\),使用 \(x – b + b\) 替换 \(x\) 得:

\(x – b + b – a \equiv 0 \pmod{x – b} \Rightarrow b – a \equiv 0 \pmod{x – b}\)

    \(x\) 的范围为 \([l, r]\),所以 \(x – b\) 范围为 \([l – b, r – b]\)。

    此时问题转化为,\([l – b, r – b]\) 范围内有多少元素是 \(b – a\) 因子。

    题目是多组测试数据,不能每组测试数据都暴力找,考虑预处理。

    定义 \(divs[i][j]\) 为 \(divs[i][j]\) 是 \(i\) 的因子,使用筛法将每个数字都存到其倍数中。

    对于每组测试数据,在 \(divs[b – a]\) 中二分有多少个数字属于\([l – b, r – b]\)。

关键代码:

vector<vector<int>> v(N + 1);
void init()
{
    for (int i = 1; i <= N; ++i)
        for (int j = i; j <= N; j += i)
            v[j].push_back(i);
}

void miyan()
{
    ll a, b, l, r;
    cin >> a >> b >> l >> r;

    ll d = b - a;
    ll L = l - b, R = r - b;

    int pos1 = ranges::lower_bound(v[d], L) - v[d].begin();
    int pos2 = ranges::upper_bound(v[d], R) - v[d].begin();

    cout << pos2 - pos1 << endl;
}

E – 小红的gcd

算法:

    \(dp\)。

思路:

    数字三角形模型。

    路径开头和结尾是矩阵起点和终点,那么就可确定好串中的第一段和最后一段的字符。

    \(n * n <= 1e6\) 且是求路径总数,考虑二维 \(dp\)。

    定义 \(dp[i][j]\) 为到达 \((i, j)\) 点的路径总数。

    由于移动只能向右和向下移动,那么 \((i, j)\) 点必然是第 \(i + j – 1\) 个到达的点;如果 \((i, j)\) 在好串中对应的字符不一样,那么 \((i, j)\) 点就不可达。

    将矩阵分为三部分处理进行状态转移即可,状态转移比较简单,看代码理解即可。

关键代码:

void miyan()
{
    int n;
    cin >> n;
    vector<string> g(n + 1);
    for (int i = 1; i <= n; ++i)
    {
        cin >> g[i];
        g[i] = ' ' + g[i];
    }

    int k = (2 * n - 1) / 3;

    char sta = g[1][1], en = g[n][n];

    vector dp(n + 1, vector<ll>(n + 1, 0));
    dp[1][1] = 1;
    for (int i = 1; i <= n; ++i)
    {
        for (int j = 1; j <= n; ++j)
        {
            int cur = i + j - 1;

            if (cur <= k)
            {
                if (g[i][j] == sta)
                {
                    if (g[i - 1][j] == sta)
                        dp[i][j] = (dp[i][j] + dp[i - 1][j]) % MOD;
                    if (g[i][j - 1] == sta)
                        dp[i][j] = (dp[i][j] + dp[i][j - 1]) % MOD;
                }
            }
            else if (cur <= 2 * k)
            {
                if (g[i][j] != sta && g[i][j] != en)
                {
                    if (cur == k + 1)
                    {
                        if (g[i - 1][j] == sta)
                            dp[i][j] = (dp[i][j] + dp[i - 1][j]) % MOD;
                        if (g[i][j - 1] == sta)
                            dp[i][j] = (dp[i][j] + dp[i][j - 1]) % MOD;
                    }
                    else
                    {
                        if (g[i - 1][j] == g[i][j])
                            dp[i][j] = (dp[i][j] + dp[i - 1][j]) % MOD;
                        if (g[i][j - 1] == g[i][j])
                            dp[i][j] = (dp[i][j] + dp[i][j - 1]) % MOD;
                    }
                }
            }
            else
            {
                if (g[i][j] == en)
                {
                    if (cur == 2 * k + 1)
                    {
                        if (g[i - 1][j] != sta && g[i - 1][j] != en)
                            dp[i][j] = (dp[i][j] + dp[i - 1][j]) % MOD;
                        if (g[i][j - 1] != sta && g[i][j - 1] != en)
                            dp[i][j] = (dp[i][j] + dp[i][j - 1]) % MOD;
                    }
                    else
                    {
                        if (g[i - 1][j] == en)
                            dp[i][j] = (dp[i][j] + dp[i - 1][j]) % MOD;
                        if (g[i][j - 1] == en)
                            dp[i][j] = (dp[i][j] + dp[i][j - 1]) % MOD;
                    }
                }
            }
        }
    }

    cout << dp[n][n] % MOD << endl;
}

F – 小红的树构造

算法:

    树,构造。

思路:

    先考虑边界情况:

  • 当 \(k == n – 1\) 时,只有一个根节点,其余全为叶子节点。
  • 当 \(k == 1\) 时,需要构造出两个非叶子节点度数互质,这样的树点数最小为 \(5\),\(n < 5\) 且 \(k == 1\) 时无解。

    树,\(n\) 个点,\(n – 1\) 条边,\(2 * n – 2\) 度。

    设存在 \(x\) 个叶子节点,\(n – x = y\) 个非叶子节点,非叶子节点度数总和 \(n + n – 2 – x = n + y – 2\) 度,所有非叶子节点度的 \(gcd = k\),那么每个非叶子节点的度都是 \(k\) 的倍数,那么 \((n + y – 2) % k == 0\)。

    将 \(n + y – 2\) 按 \(k\) 为一单位分为 \(d\) 份,每个非叶子节点会被分配得到整数份。

    考虑枚举 \(x\):

  • 如果当前 \(x\) 满足 \(n + y – 2\) 是 \(k\) 的倍数且 \((n + y – 2) / k\) 大于等于 \(y\),就说明当前 \(x\) 存在合法构造;
  • 为 \(y – 1\) 个非叶子节点每个分配 \(k\) 度,最后一个非叶子节点分配 \((n + y – 2) – k * (y – 1)\) 度;
  • 将所有非叶子节点连成一条链,除去两端的叶子节点消耗 \(1\) 度外,剩余每个消耗 \(2\) 度,共消耗 \(2 * y – 2\) 度;
  • 最后非叶子节点共剩余 \((n + y – 2) – 2 * y – 2 = n – y = x\) 度,根据非叶子节点的度数连接对应个数的叶子节点即可。

关键代码:

void miyan()
{
    int n, k;
    cin >> n >> k;

    if (k == 1)
    {
        if (n < 5)
        {
            cout << "No" << endl;
            return;
        }

        cout << "Yes" << endl;
        cout << 1 << ' ' << 2 << endl;
        cout << 3 << ' ' << 2 << endl;
        cout << 4 << ' ' << 2 << endl;
        cout << 4 << ' ' << 5 << endl;

        for (int i = 6; i <= n; ++i)
            cout << 5 << ' ' << i << endl;

        return;
    }

    if (k == n - 1)
    {
        cout << "Yes" << endl;
        for (int i = 2; i <= n; ++i)
            cout << 1 << ' ' << i << endl;

        return;
    }

    for (int x = 2; x <= n - 2; ++x)
    {
        int y = n - x;

        int du = n + y - 2;

        if (du % k)
            continue;
        if (du / k < y)
            continue;

        cout << "Yes" << endl;

        vector<int> cnt(n + 1, 0);
        for (int i = x + 1; i < n; ++i)
        {
            cnt[i] = k;
            du -= k;
        }

        cnt[n] = du;

        for (int i = x + 1; i < n; ++i)
        {
            cout << i << ' ' << i + 1 << endl;
            --cnt[i], --cnt[i + 1];
        }

        int u = 1;
        for (int i = x + 1; i <= n; ++i)
        {
            while (cnt[i])
            {
                --cnt[i];
                cout << i << ' ' << u++ << endl;
            }
        }

        return;
    }

    cout << "No" << endl;
}
暂无评论

发送评论 编辑评论


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