Codeforces Round 1006 (Div. 3)

A. cntew World, cntew Me, cntew Array

题目大意

给你一个长为n的全0数组,每个位置可以修改为不超过p的绝对值的数字,要求和为k,求最小操作次数,不可能输出-1

解题思路

显然前面尽可能的拉满,然后看最后需不需要额外补一个就行

代码实现

#include <bits/stdc++.h>

using i64 = long long;

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

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n, k, p;
        std::cin >> n >> k >> p;

        k = std::abs(k);
        if (n * p < k) {
            std::cout << -1 << "\n";
        } else {
            std::cout << (k + p - 1) / p << "\n";
        }
    }
}

B. Having Been a Treasurer in the Past, I Help Goblins Deceive

题目大意

给你一个字符串只包含 "-" 和 "_",让你重排字符串,问最多能有多少子序列是 "-_-"

解题思路

显然把"_"放中间,"-"平均放两边是最多的

代码实现

#include <bits/stdc++.h>

using i64 = long long;

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

    int tt;
    std::cin >> tt;

    while (tt--) {
        i64 n, cnt = 0;
        std::cin >> n;

        std::string s;
        std::cin >> s;

        for (auto ch : s) {
            cnt += ch == '_';
        }

        std::cout << cnt * ((n - cnt) / 2 * ((n - cnt + 1) / 2)) << "\n";
    }
}

C. Creating Keys for StOansrages Has Become My Main Skill

题目大意

给定n和x,要求用不超过n个数字使得它们按位或等于x,同时要让这些数字的mex尽可能大

解题思路

枚举mex,如果当前mex不会让x产生变化则一直枚举下去

代码实现

#include <bits/stdc++.h>

using i64 = long long;

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

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n, x, mex = 0, cnt = 0;
        std::cin >> n >> x;

        while (mex < n && ((mex & x) == mex)) {
            cnt |= mex;
            mex++;
        }

        if (mex == n && cnt != x) {
            mex--;
        }

        for (int i = 0; i < n; i++) {
            std::cout << (i < mex ? i : x) << " \n"[i == n - 1];
        }
    }
}

D. For Wizards, the Exam Is Easy, but I Couldn't Handle It

题目大意

允许操作一次,把位于l的数字放到r,求让逆序对最少的任意一组lr

解题思路

n的范围很小,因此暴力枚举每一个i换到右边的每一个位置的时候,让顺序逆序倒置的数量差求个最大值即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

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

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n;
        std::cin >> n;

        std::vector<int> a(n);
        for (int i = 0; i < n; i++) {
            std::cin >> a[i];
        }

        int l = 0, r = 0, cnt = 0;
        for (int i = 0; i < n; i++) {
            int cnt1 = 0, cnt2 = 0;
            for (int j = i + 1; j < n; j++) {
                cnt1 += a[i] > a[j];
                cnt2 += a[i] < a[j];
                if (cnt < cnt1 - cnt2) {
                    l = i, r = j;
                    cnt = cnt1 - cnt2;
                }
            }
        }

        std::cout << l + 1 << " " << r + 1 << "\n";
    }
}

E. Do You Love Your Hero and His Two-Hit Multi-Target Attacks?

题目大意

构造不超过五百个点对,使他们之间欧氏距离等于曼哈顿距离的点对数量为k

解题思路

首先计算全在一条线上的数量,发现远超最大的要求,而最小值显然就是0,因此考虑会有多条平行线段,发现他们对目标值的贡献大小是可控的,所以答案就在其中,每次新开一条不重叠的线段一直算贡献直到小于k的最大,重复直到k为0即可

代码实现

#include <bits/stdc++.h>

using i64 = long long;

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

    int tt;
    std::cin >> tt;

    while (tt--) {
        int k, x = 0, y = 0, cnt = 0;
        std::cin >> k;
        
        std::vector<std::array<int, 2>> ans;
        while (cnt < k) {
            std::vector<std::array<int, 2>> xy;
            for (int i = 0; y < k; i++) {
                if (cnt + i > k) {
                    break;
                }
                xy.push_back({x, y});
                ans.push_back({x, y});
                cnt += i;
                x++;
            }
            y++;
        }

        std::cout << ans.size() << "\n";
        for (auto [x, y] : ans) {
            std::cout << x << " " << y << "\n";
        }
    }
}

F. Goodbye, Banker Life

题目大意

类似杨辉三角,其中把加法换成异或,输出第n行

解题思路

显然输出的元素不是0就是k,打表发现组合数为偶数的输出0,奇数的输出k,于是可以转换为对组合数%2(此处的组合数是 Cn1m1 ),用卢卡斯定理即可求得答案(当mod=2时有一个结论, Cnm%2 等价于 n&m==m

代码实现

// 做法1
#include <bits/stdc++.h>

using i64 = long long;

i64 ksm(i64 a, i64 n, i64 mod) {
    i64 res = 1;
    a = (a % mod + mod) % mod;
    while (n) {
        if (n & 1) {
            res = (a * res) % mod;
        }
        a = (a * a) % mod;
        n >>= 1;
    }
    return res;
}

int C(int n, int m, int mod) {
    if (m > n) {
        return 0;
    }
    int res = 1;
    for (int i = 1, j = n; i <= m; i++, j--) {
        res = (i64)res * j % mod;
        res = (i64)res * ksm(i, mod - 2, mod) % mod;
    }
    return res;
}

int lucas(i64 a, i64 b, i64 p) {
    if (a < p && b < p) {
        return C(a, b, p);
    }
    return (i64)C(a % p, b % p, p) * lucas(a / p, b / p, p) % p;
}

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

    int tt;
    std::cin >> tt;
    
    while (tt--) {
        int n, k;
        std::cin >> n >> k;

        for (int i = 0; i < n; i++) {
            std::cout << lucas(n - 1, i, 2) * k << " \n"[i == n - 1];
        }
    }
}
// 做法2
#include <bits/stdc++.h>

using i64 = long long;

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

    int tt;
    std::cin >> tt;

    while (tt--) {
        int n, k;
        std::cin >> n >> k;

        for (int i = 0; i < n; i++) {
            std::cout << ((n - 1 & i) == i) * k << " \n"[i == n - 1];
        }
    }
}

G. I've Been Flipping Numbers for 300 Years and Calculated the Sum

题目大意

给你n,k,求2-k进制下的n反转后变回十进制的和,对答案模1e9+7

解题思路

可以发现k>n的部分只有一位, nn 的部分会有两位,观察数据范围可以发现,对于根号的复杂度是可以容忍的,因此把求和分成三部分

  • k > n
  • 2 - n
  • n - n

对于这个两位数(n/i, n%i),反转之后是(n%in/i),对于这些向下取整相同的部分(设这个区间是lr),他们的余数是一个等差数列(设首项a=n%l,公差d=n/i),可以用分块来解决

ans=i=lr(a(il)d)i+d
=(rl+1)d+i=lr(ai(i2il)d)

sum1=i=lri sum2=i=lri2

ans=(rl+1)d+sum1a(sum2sum1l)d
ans=(rl+1)d+sum1nsum2d

代码实现

#include <bits/stdc++.h>

using i64 = long long;
const int MOD = 1e9 + 7;

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

    int tt;
    std::cin >> tt;

    while (tt--) {
        i64 n, k, ans = 0;
        std::cin >> n >> k;

        if (k > n) {
            ans = ans + (k - n) % MOD * n % MOD;
            k = n;
        }

        for (int i = 2; i <= std::min((i64)std::sqrt(n), k); i++) {
            i64 x = n, res = 0;
            while (x) {
                res = (res * i + x % i) % MOD;
                x /= i;
            }
            ans = (ans + res) % MOD;
        }

        auto sum1 = [&](i64 l, i64 r) -> i64 { return (r * (r + 1) / 2 - l * (l + 1) / 2) % MOD; };
        auto sum2 = [&](i64 l, i64 r) -> i64 { return (r * (r + 1) * (2 * r + 1) / 6 - l * (l + 1) * (2 * l + 1) / 6) % MOD; };

        for (int l = sqrt(n) + 1, r; l <= k; l = r + 1) {
            r = std::min(n / (n / l), k);
            i64 a = n % l, d = n / l;
            ans += (r - l + 1) * d % MOD;
            ans += sum1(l - 1, r) * n % MOD;
            ans -= sum2(l - 1, r) * d % MOD;
        }

        std::cout << (ans % MOD + MOD) % MOD << "\n";
    }
}
posted @   udiandianis  阅读(66)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架
  1. 1 山海不可平 CMJ
山海不可平 - CMJ
00:00 / 00:00
An audio error has occurred.

纯音乐,请欣赏

点击右上角即可分享
微信分享提示