代码源挑战赛 Round 7

125 阅读3分钟

[R7A] K 的倍数

bs.daimayuan.top/p/37

求区间 [L, R] 中 K 的倍数的个数。

1LR1061K106 1≤L≤R≤10^6,1≤K≤10^6

法 1: 暴力枚举

因为数据集不大,所以可以直接遍历区间 [L, R]。

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

int main() {
    int l, r, k, ans = 0;
    cin >> l >> r >> k;

    for (int i = l; i <= r; i++) {
        if (i % k == 0) {
            ans++;
        }
    }
    cout << ans << endl;
    return 0;
}

法 2: 前缀和思想

因为区间 [1, R] 中 K 的倍数的个数为: R / K

所以区间 [L, R] 的个数 = 区间 [1, R] 的个数 - 区间 [1, L - 1] 的个数。

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

int main() {
    int l, r, k, ans = 0;
    cin >> l >> r >> k;

    ans = r / k - (l - 1) / k;
    cout << ans << endl;
    return 0;
}

[R7B] 炸弹

bs.daimayuan.top/p/38

给定一个由 @ (表示炸弹)和 . 组成的 n * m 的字符矩阵,

位于 (i, j) 的炸弹会炸到满足 ∣x - i∣+∣y - j∣≤ 3 的任意格子 (x, y)。

求每个格子会被多少个炸弹炸到。数据范围:1n,m10001≤n,m≤1000

准备工作:

const int N = 1010, M = 1010;
int n, m, ans[N][M];     // 记录每个格子会被多少个炸弹炸到

// 判断格子坐标是否合法
bool in_range(int x, int y) {
    return (x >= 0 && x <= n && y >= 0 && y <= m);
}

// 通过坐标 (i, j) 找到满足 ∣x - i∣ + ∣y - j∣ ≤ 3 的合法格子 (x, y)
for (int x = i - 3; x <= i + 3; x++) {
    for (int y = j - 3; y <= j + 3; y++) {
        if ((abs(x - i) + abs(y - j) <= 3) && in_range(x, y)) {
            ...
        }
    }
}

方法 1: 通过炸弹位置,找到被它炸到的格子

void solve(int i, int j) {
    if (s[i][j] != '@') {
        return;
    }
    for (int x = i - 3; x <= i + 3; x++) {
        for (int y = j - 3; y <= j + 3; y++) {
            if ((abs(x - i) + abs(y - j) <= 3) && in_range(x, y)) {
                ans[x][y]++;
            }
        }
    }
} 

方法 2: 对于每个格子,找到它附近的炸弹

void solve(int i, int j) {
    for (int x = i - 3; x <= i + 3; x++) {
        for (int y = j - 3; y <= j + 3; y++) {
            if ((abs(x - i) + abs(y - j) <= 3) && in_range(x, y) && s[x][y] == '@') {
                ans[i][j]++;
            }
        }
    }
} 

完整代码

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

const int N = 1010, M = 1010;
char s[N][M];
int n, m, ans[N][M];

bool in_range(int x, int y) {
    return (x >= 0 && x <= n && y >= 0 && y <= m);
}

void solve(int i, int j) {
    if (s[i][j] != '@') {
        return;
    }
    for (int x = i - 3; x <= i + 3; x++) {
        for (int y = j - 3; y <= j + 3; y++) {
            if ((abs(x - i) + abs(y - j) <= 3) && in_range(x, y)) {
                ans[x][y]++;
            }
        }
    }
} 

int main() {
    cin >> n >> m;
    for (int i = 0; i < n; i++) {
        scanf("%s", s[i]);
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            solve(i, j);
        }
    }

    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            printf("%d ", ans[i][j]);
        }
        printf("\n");
    }
    return 0;
}

[R7C] 二维 gcd 和

bs.daimayuan.top/p/39

i=1Nj=1M(gcd(i,N)×gcd(j,M))\sum_{i=1}^N\sum_{j=1}^M(gcd(i, N) \times gcd(j, M)) mod 998244353

对于 50% 的数据, N,M2000N, M \leq 2000

对于 100% 的数据, 1N,M2×1061 \leq N, M \leq 2 \times 10^6

gcd: 最大公约数

int gcd(int x, int y) {
    if (y == 0) {
        return x;
    }
    return gcd(y, x % y);
}

50 分的做法: O(NM)O(N * M)

void solve() {
    for (int i = 1; i <= n; i++) {
        int di = gcd(i, n);
        for (int j = 1; j <= m; j++) {
            int dj = gcd(j, m);
            ans = (ans + 1LL * di * dj) % P;
        }
    }
}

100 分的做法: O(N+M)O(N + M)

  提取公因数: i=1Nj=1M(gcd(i,N)×gcd(j,M))=i=1N(gcd(i,N)×j=1M(gcd(j,M)))\sum_{i=1}^N\sum_{j=1}^M(gcd(i, N) \times gcd(j, M)) = \sum_{i=1}^N(gcd(i, N) \times \sum_{j=1}^M(gcd(j, M)))

  因此可以先把 j=1M(gcd(j,M))\sum_{j=1}^M(gcd(j, M)) 计算出来,就可以将原来的两层循环简化成一层循环。

void solve() {
    int dj = 0;
    for (int j = 1; j <= m; j++) {
        dj = (gcd(j, m) + dj) % P; 
    }
    for (int i = 1; i <= n; i++) {
        int di = gcd(i, n);
        ans = (ans + 1LL * di * dj) % P;
    }
}

完整代码

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

const int P = 998244353;
int n, m;
long long ans = 0;

int gcd(int x, int y) {
    if (y == 0) {
        return x;
    }
    return gcd(y, x % y);
}

void solve() {
    int dj = 0;
    for (int j = 1; j <= m; j++) {
        dj = (gcd(j, m) + dj) % P; 
    }
    for (int i = 1; i <= n; i++) {
        int di = gcd(i, n);
        ans = (ans + 1LL * di * dj) % P;
    }
}

int main() {
    cin >> n >> m;
    solve();
    cout << ans << endl;
    return 0;
}