【CF比赛记录】Codeforces Round 1013 (Div. 3)-牛翰网

【CF比赛记录】Codeforces Round 1013 (Div. 3)

比赛链接
本文发布于博客园,会跟随补题进度实时更新,若您在其他平台阅读到此文,请前往博客园获取更好的阅读体验。
跳转链接:https://www.cnblogs.com/TianTianChaoFangDe/p/18796248

开题情况

图片[1]-【CF比赛记录】Codeforces Round 1013 (Div. 3)-牛翰网
打回蓝了。
很基础的一场,不过怎么有人会因为没取模白挂两发啊啊啊!太羞耻了!

A. Olympiad Date

很简单,判断一下日期里面的数字什么时候全部数量充足就行了。

点击查看代码

//20250103

void solve()
{
    int n;std::cin >> n;
    std::vector<int> a(n);
    std::vector<int> cnt(10);

    for(auto &i : a) {
        std::cin >> i;
    }

    auto check = [&]() -> bool {
        if(cnt[0] < 3)return false;
        if(cnt[1] < 1)return false;
        if(cnt[2] < 2)return false;
        if(cnt[3] < 1)return false;
        if(cnt[5] < 1)return false;

        return true;
    };

    for(int i = 0;i < n;i ++) {
        cnt[a[i]] ++;

        if(check()) {
            std::cout << i + 1 << '\n';
            return;
        }
    }

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

B. Team Training

首先很明显从大到小排序,然后双指针搜索就行了。

点击查看代码

void solve()
{
    int n;std::cin >> n;
    i64 x;std::cin >> x;
    std::vector<i64> a(n + 1);

    for(int i = 1;i <= n;i ++)std::cin >> a[i];

    std::sort(a.begin() + 1, a.end(), std::greater());

    int sum = 0;
    for(int i = 1, j = 1;i <= n;i = j + 1) {
        j = i;
        while(j + 1 <= n && a[j] * (j - i + 1) < x)j ++;

        if(a[j] * (j - i + 1) >= x) {
            sum ++;
        }
    }

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

C. Combination Lock

说实话这题做了有点久,因为验证结论的时候算错了一步导致误以为结论是错的。
根据样例猜的,偶数一定无解,奇数的话,把题目样例都变成 \(1\) 开头,很明显就是先奇数后偶数就行。

点击查看代码

#include <bits/stdc++.h>
#define inf32 1e9
#define inf64 2e18
#define ls o << 1
#define rs o << 1 | 1

using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned int;

const int N = 2e5 + 9;

void solve()
{
    int n;std::cin >> n;

    if(n % 2 == 0) {
        std::cout << -1 << '\n';
        return;
    }

    for(int i = 1;i <= n;i += 2) {
        std::cout << i << ' ';
    }

    for(int i = 2;i <= n;i += 2) {
        std::cout << i << ' ';
    }

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

D. Place of the Olympiad

凳子越长肯定可以坐越多人,所以答案具有单调性,因此可以二分。
在二分的 check 中,尽可能只留一个格子作为过道,使能坐的人尽可能多,看能否坐下所有人。

点击查看代码

void solve()
{
    i64 n, m, k;std::cin >> n >> m >> k;

    i64 l = 0, r = m + 1;

    auto check = [&](i64 x) -> bool {
        i64 ch = m % (x + 1);
        i64 sum = m / (x + 1) * x * n;

        sum += ch * n;
        return sum >= k;
    };

    while(l + 1 != r) {
        int mid = l + r >> 1;
        if(check(mid))r = mid;
        else l = mid;
    } 

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

E. Interesting Ratio

根据唯一分解定理,我们可以把两个数 \(x\)\(y\) 分解成一系列素数的素数的幂次的乘积,并且有:两个数的最大公因数,就是对每个素数的指数取小的那个乘起来,两个数的最小公倍数,就是对每个素数的指数取大的那个乘起来,也就是(\(k\) 为素数):

\[x = 2 ^ {a_2} \times 3 ^ {a_3} \times 5 ^ {a_5} … \times k ^ {a_k} \]

\[y = 2 ^ {b_2} \times 3 ^ {b_3} \times 5 ^ {b_5}… \times k ^ {b_k} \]

\[\gcd(x, y) = 2 ^ {\min(a_2, b_2)} \times 3 ^ {\min(a_3, b_3)} \times 5 ^ {\min(a_5, b_5)} … \times k ^ {\min(a_k, b_k)} \]

\[\operatorname{lcm}(x, y) = 2 ^ {\max(a_2, b_2)} \times 3 ^ {\max(a_3, b_3)} \times 5 ^ {\max(a_5, b_5)} … \times k ^ {\max(a_k, b_k)} \]

因此,如果满足两个数的最小公倍数和最大公因数的商是一个素数,这两个数应该有且仅有一个素数的指数不同,并且差值为 \(1\)
那么这题的思路就很明确了,对于每一个素数,看他在范围内能乘多少个数,就是这个素数对应的答案。
对所有素数的答案求和即为总的答案。

点击查看代码

#include <bits/stdc++.h>
#define inf32 1e9
#define inf64 2e18
#define int long long
#define ls o << 1
#define rs o << 1 | 1

using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned int;

const int N = 1e7 + 9;
int prime[N];
bool notprime[N];
int tot = 0;

void init() {
    notprime[0] = notprime[1] = true;

    for(int i = 2;i <= 10'000'000;i ++) {
        if(!notprime[i])prime[++ tot] = i;

        for(int j = 1;j <= tot && i * prime[j] <= 10'000'000;j ++) {
            notprime[i * prime[j]] = true;
            if(i % prime[j] == 0) {
                break;
            }
        }
    } 
}

void solve()
{
    int n;std::cin >> n;

    i64 ans = 0;
    for(int i = 1;i <= tot && prime[i] <= n;i ++) {
        int a = 1;
        int b = prime[i];
        ans += n / b;
    }

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

signed main()
{
    std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);

    init();

    int t = 1;std::cin >> t;
    while(t --)solve();

    return 0;
}

F. Igor and Mountain

没错,就是这个题,赛时没看到输出那里有个 998244353,挂了一发,血压起来了。
这个题是一个很简单的 DP,因为题目限制得很明确:

  • 只能一层一层爬。
  • 每一层最多使用两个可抓点。

那么思路就很明晰了,首先从低一层往当前层进行状态转移,然后再在同层进行状态转移。
由于手臂距离为 \(d\),所以低一层的第 \(j\) 个点位向当前层转移的范围应该是 \([j – \sqrt{d ^ 2 – 1}, j – \sqrt{d ^ 2 – 1}]\),由于相邻两个平方数之间的差值至少都是 \(1\),因此 \(\sqrt{d ^ 2 – 1} = d – 1\),避免浮点数精度误差。
同层转移也是一样的,对于当前层第 \(j\) 个点的转移范围应该是 \([j – d, j + d]\)
但是如果暴力转移,复杂度为 \(O(nm^2)\),因此要考虑优化:我们发现,每一个状态向周围的转移都是一个区间,那么我们就可以使用差分来优化区间修改,时间复杂度优化为 \(O(nm)\),足以通过此题。

点击查看代码(省略了取模类)

#include <bits/stdc++.h>
#define inf32 1e9
#define inf64 2e18
#define int long long
#define ls o << 1
#define rs o << 1 | 1

using i64 = long long;
using u64 = unsigned long long;
using u32 = unsigned int;

void solve()
{
    int n, m, d;std::cin >> n >> m >> d;
    std::vector<std::vector<char>> a(n + 1, std::vector<char>(m + 1));
    int x = d - 1;

    for(int i = 1;i <= n;i ++) {
        for(int j = 1;j <= m;j ++) {
            std::cin >> a[i][j];
        }
    }

    std::vector<std::vector<Z>> dp(n + 1, std::vector<Z>(m + 1, 0));

    std::vector<Z> f(m + 2, 0);
    for(int i = n;i >= 1;i --) {
        for(auto &i : f)i = 0;
        if(i == n) {
            for(int j = 1;j <= m;j ++) {
                if(a[n][j] == 'X')dp[n][j] = 1;
                else dp[n][j] = 0;
            }
        } else {
            for(int j = 1;j <= m;j ++) {
                int d = x;
                if(a[i + 1][j] == 'X') {
                    int l = std::max(j - d, 1ll);
                    int r = std::min(j + d, m);
                    f[l] += dp[i + 1][j];
                    f[r + 1] -= dp[i + 1][j];
                }
            }
            for(int j = 1;j <= m;j ++) {
                f[j] += f[j - 1];
                if(a[i][j] == 'X') {
                    dp[i][j] += f[j];
                }
            }
        }

        for(auto &i : f)i = 0;
    
        for(int j = 1;j <= m;j ++) {
            if(a[i][j] == 'X') {
                int l = std::max(j - d, 1ll);
                int r = std::min(j + d, m);
                f[l] += dp[i][j];
                f[j] -= dp[i][j];
                f[j + 1] += dp[i][j];
                f[r + 1] -= dp[i][j];
            }
        }
        
        for(int j = 1;j <= m;j ++) {
            f[j] += f[j - 1];
            if(a[i][j] == 'X') {
                dp[i][j] += f[j];
            }
        }
    }

    Z sum = 0;
    for(int j = 1;j <= m;j ++) {
        sum += dp[1][j];
    }

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

来源链接:https://www.cnblogs.com/TianTianChaoFangDe/p/18796248

请登录后发表评论

    没有回复内容