A 国家集训队

题解

注意数据已经是有序的,我还搞了个排序,我是智障 所以只需要将第5个人到第16个人的成绩都预设成300,再把前4个人的成绩都预设成0,再看有没有人能超过第4个人就行了

ac代码

#include <iostream>
using namespace std;
const int N = 20;
int a[N], ans = 4;
int main() {
    for (int i = 1; i <= 16; i++) cin >> a[i];
    for (int i = 5; i <= 16; i++) {
        if (a[i] + 300 > a[4])
            ans++;
        else
            break;
    }
    cout << ans;
    return 0;
}

B 撑伞

题解

想要所有人都不被淋,那么最长的距离就是 \(n+2×D\) ,每个人如果有伞的话,能覆盖到的地方就是 \((1+2×D)\),相除就行了

ac代码

#include <iostream>
using namespace std;
int n, k;
int main() {
    cin >> n >> k;
    cout << (n + 2 * k) / (2 * k + 1);
    return 0;
}

C 走遍城市

题解

非常简单的数学题,也就是找出来一个数 \(x\) ,使得它和初始位置能凑出来 \(p_i\) 就行了,具体看代码

ac代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int p[N];
int n, x, ans;
int main() {
    cin >> n >> x;
    for (int i = 1; i <= n; i++) {
        int k;
        cin >> k;
        ans = __gcd(ans, abs(k - x));
    }
    cout << ans;
    return 0;
}

D 魔法筷子

题解

我们可以只考虑第三个情况,一二情况直接贪心

我们可以假设我们的 A B C 筷子初始为0,然后累加

注意最后减30,因为等于0的时候,实际上不是合并筷子

ac 代码

#include <iostream>
using namespace std;
const int N = 10;
int l[N];
int n, ans = 0x3f3f3f3f, A, B, C;
void dfs(int u, int x, int y, int z, int magic) {
    if (x && y && z)
        ans = min(ans, abs(x - A) + abs(y - B) + abs(z - C) + magic - 30);
    if (u > n)
        return;
    dfs(u + 1, x + l[u], y, z, magic + 10);
    dfs(u + 1, x, y + l[u], z, magic + 10);
    dfs(u + 1, x, y, z + l[u], magic + 10);
    dfs(u + 1, x, y, z, magic);
}
int main() {
    cin >> n >> A >> B >> C;
    for (int i = 0; i < n; i++) cin >> l[i];
    dfs(0, 0, 0, 0, 0);
    cout << ans;
    return 0;
}

E 马农

题解

这道题可以用二维前缀和来优化

注意这题有两种情况,题目的图片有就不多赘述了

我使用了一个cnt数组来记录收益的情况并加了一个偏移量来防止负数的情况

首先两重循环枚举交点,注意是枚举到 \(n-1\) ,不然就没位置了,然后再分别枚举两个矩形的位置,把第一个矩形算出来的收益用cnt数组记录,然后另外一个矩形的收益如果跟第一个矩形一样,答案就加上

不能用memset初始化,我们可以把所有用到的位置记录下来,然后将这些位置归0就行了,不然会2000万会爆

ac代码

#include <iostream>
using namespace std;
int x;
const int N = 105, convertnum = 1000000;  //防止负数
short cnt[20000005];
int nums[N];  //去重
int sum[N][N];
int top, ans, n;
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            cin >> x;
            sum[i][j] = x + sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1];
        }
    }
    //两种情况,一种两个都横着,一种一个竖着,一个横着
    // i枚举到n-1,不然没位置了 j同理
    for (int i = 1; i < n; i++) {
        for (int j = 1; j < n; j++) {
            for (int k = 1; k <= i; k++) {
                for (int l = 1; l <= j; l++) {
                    int tmp = sum[i][j] - sum[i][l - 1] - sum[k - 1][j] + sum[k - 1][l - 1];
                    if (!cnt[tmp + convertnum])
                        nums[++top] = tmp + convertnum;
                    cnt[tmp + convertnum]++;
                }
            }
            for (int k = n; k > i; k--) {
                for (int l = n; l > j; l--) {
                    int tmp = sum[k][l] - sum[i][l] - sum[k][j] + sum[i][j];
                    ans += cnt[tmp + convertnum];
                }
            }
            //后面还要用
            for (int k = 1; k <= top; k++) cnt[nums[k]] = 0;
            top = 0;
        }
    }
    for (int i = 1; i < n; i++) {
        for (int j = n; j > 1; j--) {
            for (int k = 1; k <= i; k++) {
                for (int l = n; l >= j; l--) {
                    int tmp = sum[i][l] - sum[k - 1][l] - sum[i][j - 1] + sum[k - 1][j - 1];
                    if (!cnt[tmp + convertnum])
                        nums[++top] = tmp + convertnum;
                    cnt[tmp + convertnum]++;
                }
            }
            for (int k = n; k > i; k--) {
                for (int l = 1; l < j; l++) {
                    int tmp = sum[k][j - 1] - sum[k][l - 1] - sum[i][j - 1] + sum[i][l - 1];
                    ans += cnt[tmp + convertnum];
                }
            }
            for (int k = 1; k <= top; k++) cnt[nums[k]] = 0;
            top = 0;
        }
    }
    cout << ans;
    return 0;
}