【解题报告】Codeforces Round #364 (Div. 2)

本文解析了Codeforces平台上的三道经典算法题目:Cards、CellsNotUnderAttack和TheyAreEverywhere,分别介绍了每道题目的核心思路及代码实现,并提供了解决问题的不同角度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接


A. Cards(Codeforces 701A)

思路

因为每个人得到的牌的点数的总和都是一样的,所以可以扫描牌组并把剩下的第一张牌 i 给第一个人,然后为他在剩下的牌中找到点数合适的另一张牌 j (也就是 a[i]+a[j]=2sumn ),这样继续下去,直到所有的牌分完(此时每个人也都分到了 2 张牌)。这样的复杂度是 O(n2) 的。(当然有更好的算法,但是没必要。)

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 110;
bool vis[maxn];
int n, sum, tmp, cnt, a[maxn], b[maxn], c[maxn];

int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        sum += a[i];
    }
    tmp = 2 * sum / n;
    cnt = 1;
    for(int i = 1; i <= n; i++) {
        if(vis[i] == true) {
            continue;
        }
        b[cnt] = i;
        for(int j = i + 1; j <= n; j++) {
            if(vis[j] == true) {
                continue;
            }
            if(a[i] + a[j] == tmp) {
                vis[j] = true;
                c[cnt] = j;
                break;
            }
        }
        cnt++;
    }
    for(int i = 1; i <= n / 2; i++) {
        printf("%d %d\n", b[i], c[i]);
    }
    return 0;
}

B. Cells Not Under Attack(Codeforces 701B)

思路

可以将问题转化为已经放的城堡能够攻击到的方格数 res 。由于每次询问都要瞬间知道 res ,所以要额外维护一些变量: R 表示有多少行有城堡, C 表示有多少列有城堡, r[i] 表示第 i 行有没有城堡, c[i] 表示第 i 列有没有城堡。假如我们要在 (x,y) 位置新放置一个城堡,先给 res 加上 n+n 。如果 r[x] true 的话,就让 res 减去 n 否则就减去 C (表示去掉 x 这行的重复覆盖部分)。如果 c[y] true 的话就然 res 减去 n 否则就减去 R (表示去掉 y 这行的重复覆盖部分)。最后处理一下 (x,y) 位置被重复加减的情况,输出 res 就行了。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
const int maxn = 1e5 + 10;
bool r[maxn], c[maxn];
ll n, m, x, y, R, C, res;

int main() {
    scanf("%I64d%I64d", &n, &m);
    while(m--) {
        scanf("%I64d%I64d", &x, &y);
        res += n + n;
        res -= r[x] ? n : C;
        R += r[x] == false;
        r[x] = true;
        res -= c[y] ? n : R;
        C += c[y] == false;
        c[y] = true;
        printf("%I64d ", n * n - res);
    }
    puts("");
    return 0;
}

思路

脑残如我想到上面这个这么麻烦的办法,实际上还有更简便的办法:没被攻击到的格子数 = 没被攻击到的行数 × 没被攻击到的列数。

代码

#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
ll n, m, x, y;
set <ll> r, c;

int main() {
    cin >> n >> m;
    while(m--) {
        cin >> x >> y;
        r.insert(x);
        c.insert(y);
        cout << (n - r.size()) * (n - c.size()) << endl;
    }
    return 0;
}

C. They Are Everywhere(Codeforces 701C)

思路

按照题给的数据量,直接枚举区间然后检查区间是否包含所有神奇宝贝是会超时的。因此我们可以用“尺取法”来解决。用首尾指针来表示目前枚举到的区间,开始先向字符串结尾移动尾指针,移动到将所有神奇宝贝包括在区间内停止(再移动也得不到最优解),然后移动首指针,直到不是所有的神奇宝贝在区间内,再移动尾指针……这样我么就能在 O(n) 的时间内解决问题。另外为了实现算法,我们还需要维护当前区间内每种神奇宝贝有多少个。

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e5 + 10;
char s[maxn];
int n, head, tail, res, cnt, num;
set<char> ss;
map<char, int> m;

int main() {
    scanf("%d%s", &n, s);
    for(int i = 0; i < n; i++) {
        ss.insert(s[i]);
    }
    num = ss.size();
    res = n;
    while(true) {
        while(cnt < num && tail < n) {
            if(m[s[tail++]]++ == 0) {
                cnt++;
            }
        }
        if(cnt < num) {
            break;
        }
        res = min(res, tail - head);
        if(--m[s[head++]] == 0) {
            cnt--;
        }
    }
    printf("%d\n", res);
    return 0;
}

(其它题目略)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值