Codeforces Round 775 (Div. 2, based on Moscow Open Olympiad in Informatics)(A~D)

A. Game

给出一个数组,由0和1组成,遇到0不能走,遇到1可以没有花费的走过去。最多只能跳一次,花费x,从i跳到i + x。问从头走到尾,最少的花费是多少。

思路:只能跳一次,所以最优的方案是从第一个为0的位置开始跳,跳到最后一个为0的位置。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N = 2e5 + 5;
int t, n;
int a[N];

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> t;
    while(t --) {
        std::cin >> n;
        int st = 0, en = 0;
        for(int i = 1; i <= n; i ++) {
            std::cin >> a[i];
            if(!st && !a[i])
                st = i - 1;
        }
        for(int i = n; i >= 1; i --) {
            if(!a[i]) {
                en = i + 1;
                break;
            }
        }
        std::cout << en - st << '\n';
    }
    return 0;
}

os:一开始读错题了,一直wa,乐

B. Game of Ball Passing

n个人传球,每个人传了a[i]次,问最少需要几个球。

思路:其实只需要考虑传球次数最多的那个人。如果最多的那个人传的次数大于其他所有人的和+1,那必须用多的球,即这个人的次数减去全部人的次数是答案;其他的情况,一个球足够。至于为什么是要+1,因为如果这个最多的人在第一个传球,那还可以多加一次传球。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N = 1e5 + 5;
int t, n;
ll a[N];

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> t;
    while(t --) {
        std::cin >> n;
        for(int i = 1; i <= n; i ++) {
            std::cin >> a[i];
        }
        std::sort(a + 1, a + 1 + n);
        if(!a[n]) {
            std::cout << 0 << '\n';
            continue;
        }
        ll sum = 0;
        bool flag = false;
        for(int i = 1; i < n; i ++) {
            sum += a[i];
            if(sum + 1 >= a[n]) {
                flag = true;
                break;
            }
        }
        std::cout << std::max((ll)1, a[n] - sum) << '\n';
    }
    return 0;
}

C. Weird Sum

给出一个n*m的二维数组,计算每一对相同的数字之间曼哈顿距离之和。

思路:因为是计算曼哈顿距离,所以完全可以x和y分开计算,统计所有相同的数字的位置,排序,按照前后相邻两个位置直接计算贡献。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
#define int long long
const int N = 1e5 + 5;
int t, n, m;
int a[N];
std::vector<int> row[N], col[N];
bool vis[N];

signed main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> n >> m;
    int cnt = 0;
    for(int i = 1; i <= n; i ++) {
        for(int j = 1; j <= m; j ++) {
            int x;
            std::cin >> x;
            if(!vis[x])
                vis[x] = true, a[++ cnt] = x;
            row[x].push_back(i);
            col[x].push_back(j);
        }
    }
    int ans = 0;
    for(int i = 1; i <= cnt; i ++) {
        int x = a[i];
        std::sort(row[x].begin(), row[x].end());
        std::sort(col[x].begin(), col[x].end());
        int len = row[x].size();
        for(int j = 1; j < len; j ++) {
            ans += (row[x][j] - row[x][j - 1]) * (len - j) * j;
            ans += (col[x][j] - col[x][j - 1]) * (len - j) * j;
        }
    }
    std::cout << ans << '\n';
    return 0;
}

D. Integral Array

给出一个数组,判断它是否满足以下条件:选择任意两个数(也可以是它本身),大数除以小数向下取整的结果都在数组中出现。

思路:因为是x / y = t,可以反过来考虑,对于x的范围,我们可以这样表示:[y * t, y * (t + 1) - 1]。所以枚举t和y,判断x的存在即可。对于区间内判断,可以采用前缀和记录。

AC Code:

#include <bits/stdc++.h>

typedef long long ll;
const int N = 1e6 + 5;
int t, n, c;
ll a[N], vis[N << 1], pre[N << 1];

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(0);
    std::cout.tie(0);
    std::cin >> t;
    while(t --) {
        std::cin >> n >> c;
        for(int i = 1; i <= 2 * c; i ++) {
            vis[i] = 0;
        }
        for(int i = 1; i <= n; i ++) {
            std::cin >> a[i];
            vis[a[i]] ++;
        }
        for(int i = 1; i <= 2 * c; i ++) {
            pre[i] = pre[i - 1] + vis[i];
        }
        bool flag = true;
        for(int i = 1; i <= c; i ++) {
            if(!vis[i]) continue;
            for(int j = 1; j * i <= c; j ++) {
                if(vis[j]) continue;
                if(pre[i * j - 1] != pre[i * (j + 1) - 1]) {
                    flag = false;
                    break;
                }
            }
            if(!flag) break;
        }
        std::cout << (flag ? "Yes" : "No") << '\n';
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值