Codeforces Round #818 (Div. 2) A-D

A. Madoka and Strange Thoughts

标签:数学

题意:

  • 给出一个n,求1到n中有多少组(a,b)使得 lcm(a,b)/gcd(a,b)>=3

思路:

众所周知lcm = a*b/gcd,把式子转化为 a*b >= 3*gcd * gcd,这样做一点用都没有
实际上这题我们可以枚举一下情况
我们令 tmp = gcd(a,b)
情况1: a = b = tmp
情况2: a = 2*tmp, b = tmp 或者 a = tmp, b =2* tmp
情况3: a = 3*tmp, b = tmp 或者 a = tmp, b =3* tmp
除此之外就没有符合的情况了
写的时候被卡了十分钟,我太菜了

代码:

#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
const int mod = 1e9 + 7;

void solve() {
    long long n;
    cin >> n;
    cout << n + 2 * (n / 2 + n / 3) << le;//对应以上三种情况
}

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

B. Madoka and Underground Competitions

标签:构造模拟

题意:

  • 有一n*n大小的矩阵,让你用.X去填充里面的方格
  • 要求矩阵中每 1 * k 和 k * 1的区域内至少含有一个X
  • 给出r和c,要求坐标(r , c)方格必须为X
  • 要求使用尽可能少的X,输出符合要求的矩阵

思路:

题目明确n为k的倍数,我们首先思考一个k*k的矩阵,只要一条对角线上为X即可
然后构造大矩阵

for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (i % k == j % k)
                cout << 'X';
            else
                cout << '.';
        }
        cout << le;

再来思考r,c,注意到我们原本式子中当i=k时输出x,此时i和j的偏差为0
我们对r和c取模比较,r%k与c%k的偏差多少 i和j的偏差就多少

代码:

#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
const int mod = 1e9 + 7;

void solve() {
    int n, k, r, c;
    cin >> n >> k >> r >> c;
    int dif = (r % k - c % k + k) % k;//两者的偏差
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if ((i - dif + k) % k == j % k)
                cout << 'X';
            else
                cout << '.';
        }
        cout << le;
    }
}

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

C. Madoka and Formal Statement

标签:贪心 思维

题意:

  • 有长度为n的数列a和b
  • 只要a[i]<=a[(i+1)%n],就可以a[i]进行加1操作
  • 问能否通过操作得到a = b

思路:

依旧分情况讨论

  • a[i] = b[i] 不用操作,一定可行
  • a[i] > b[i] 寄
  • a[i] < b[i] ,a[i]的理论最大值为b[(i+1)%n]+1,若b[i]大于理论最大值,则不可行

代码:

#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
const int mod = 1e9 + 7;

void solve() {
    int n;
    cin >> n;
    vector<int> a(n), b(n);
    for (int i = 0; i < n; i++) cin >> a[i];
    for (int i = 0; i < n; i++) cin >> b[i];
    bool f = 1;
    for (int i = 0; i < n; i++) {
        if (a[i] > b[i]) f = 0;//情况二
        if (a[i] < b[i] && b[i] > b[(i + 1) % n] + 1) f = 0;//情况三
    }
    if (f)
        cout << "YES" << le;
    else
        cout << "NO" << le;
}

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

D. Madoka and The Corruption Scheme

标签:博弈 二叉树 排列组合

题意:

  • 2n个人打OSU(音游,太难玩了)
  • 进行n轮比赛,每轮比赛中两两对战
  • 比赛特别黑,Madoka可以决定对战中谁胜谁负,并且第一轮可以重新排序比赛选手
  • 主办方有k次操作机会,每次操作可反转本轮比赛结果,即在Madoca判完本轮每个选手的胜负之后反转结果
  • 主办方希望最终胜利者的编号越大越好,Madoka希望最终胜利者的编号越小越好
  • 双方均采取最优策略 输出可能的最终胜利者的编号请添加图片描述

思路:

看了其他人题解才知道,这题居然是排列组合,原理也是非常巧妙的
画个比较简陋的图来解释一下
我们将
请添加图片描述
我们将左边定义为胜利边,右边为失败边,每次将失败反转需要消耗一次操作
定义根节点权值为0,然后以上述规则来画,得到每个节点的权值
考虑贪心的思想,我们应该将大的数字放到大的权值上面,比如当n=3时,我们将
23 放到权值为3的地方去,表示需要三次操作才能得到
观察第四行 我们发现0 1 2 3 4各点的数量符合杨辉三角的分布
因此答案就等于2n 减去全部权值大于k的数的数量

代码:

#define fst std::ios::sync_with_stdio(false), std::cin.tie(0), std::cout << std::fixed << std::setprecision(20)
#define le "\n"
#define ll long long
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 50;
const int mod = 1e9 + 7;
ll fact[N], inv[N];
ll qpow(ll a, ll b) {
    ll res = 1;
    while (b) {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

ll C(int a, int b) { return (fact[b] * inv[a] % mod) * inv[b - a] % mod; }

ll qsm(int a, int b) {
    ll base = a, res = 1;
    while (b) {
        if (b & 1) res = res * base % mod;
        base = base * base % mod;
        b >>= 1;
    }
    return res;
}

int main() {
    int n, k;
    cin >> n >> k;

    fact[0] = inv[0] = 1;
    for (int i = 1; i <= n; i++) fact[i] = fact[i - 1] * i % mod;
    inv[n] = qpow(fact[n], mod - 2) % mod;
    for (ll i = n - 1; i >= 1; i--) inv[i] = inv[i + 1] * (i + 1) % mod;

    ll ans = qsm(2, n);
    if (k >= n) {
        cout << ans << le;
    } else {
        for (int i = k + 1; i <= n; i++) {
            ans = ((ans - C(i, n)) % mod + mod) % mod;
        }
        cout << ans << endl;
    }

    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值