[Codeforces] Round #775 (div 2)

A. Game

题意

给出一串只包含0或1的序列,遇到0时必须跳过,两个相邻1之间可以不消耗费用进行移动,至多只能跳一次,从i跳到i + x会产生费用x,求最小费用

思路

因为只能跳一次,所以必须要把所有0的位置都跳过
离起点能到达的最远的1开始跳,跳到离终点最远的1的位置
如111001010100111,我们就从i=3跳到i=13的位置
用两次while循环找一下跳跃的起点终点即可

代码

#include<bits/stdc++.h>
#include <iostream>
#include <ctime>
using namespace std;
//==========================================
const int maxn = 1e5+5;
int a[maxn];
signed main(signed argc, char const *argv[])
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
#ifdef LOCAL
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    //======================================
    int T;
    cin >> T;
    while(T --) {
        int n;
        cin >> n;
        for(int i = 1; i <= n; i ++) {
            cin >> a[i];
        }
        int flag = 0, fg = 0;
        int ans = 0;
        while(n) {
            if(a[n] != 1) break;
            n --;
        }
        int l = 1;
        while(l) {
            if(a[l] != 1) break;
            l ++;
        }
        if(n == 0) {
            cout << 0 << endl;
        }
        else cout << n - l + 2 << endl;
    }
    //======================================

    return 0;   
}

/*DETAILS

*/

B. Game of Ball Passing

题意

给定一个序列a,a[i]代表每个人传球的次数,求最少需要多少个球
可以从任意人开始传球,传到任意人(不包括自己)

思路

这题昨天卡了巨久,我真是太菜了
首先考虑全是0的情况,没有人需要传球,所以只需要0个球
再考虑一般情况
对于一个人传球,如果球传回自己手上,相当于消耗了某人和自己的一次传球次数
我们想要每次将传球次数最多的人的次数减少,所以最后必定只剩下一个人的传球次数
如果他的传球次数剩1,那么只需一个球即可
否则就需要maxn - (sum - maxn)个球

代码

void solve() {
    int n;
    cin >> n;
    ll sum = 0, maxn = 0;
    for(int i = 1; i <= n; i ++) {
        cin >> a[i];
        sum += a[i];
        maxn = max(maxn, a[i]);
    }
    if(maxn == 0) {
        cout << 0 << endl;
        return;
    }
    sum -= maxn;
    if(maxn > sum) cout << maxn - sum << endl;
    else cout << 1 << endl;
}

C. Weird Sum

题意

求矩阵中所有相同颜色块对之间的曼哈顿距离

思路

对于曼哈顿距离:d(i, j)=|xi - xj| + |yi - yj|
就是两点间y轴差+x轴差
题目要我们求所有相同颜色块对之间的曼哈顿距离,暴力求肯定是不行的
考虑每个对之间会产生一个xi, xj, yi, yj
可以将其对所有相同颜色分行列进行合并求解
对于列,每新增一个相同颜色时,会对之前的这个颜色的总数都产生一个yj,总值是前面的总数乘yj,再减去前面的yi总和
对于行同理

代码

#include<bits/stdc++.h>
#include <iostream>
#include <ctime>
using namespace std;
//==========================================
const int maxn = 1e5+5;
typedef long long ll;
vector<int> col[maxn], row[maxn];
ll cal(vector<int> &color) {
    sort(color.begin(), color.end());
    ll pre = 0, res = 0, now = 0;
    for(auto j : color) {
        res += now * j - pre;//每次增加的值为列数*列值 - 列值总和
                             //(相当于把曼哈顿距离整体化,对于每个点对的距离都会产生一个j,再减掉之前加过的j即可)
        now ++;   //now维护当前颜色的列数量
        pre += j; //pre维护当前列值总和
    }
    return res;
}
signed main(signed argc, char const *argv[])
{
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
#ifdef LOCAL
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    //======================================
    int n, m;
    cin >> n >> m;
    int x;
    for(int i = 1; i <= n; i ++) {
        for(int j = 1; j <= m; j ++) {
            cin >> x;
            col[x].push_back(j);
            row[x].push_back(i);
        }
    }
    ll ans = 0;
    for(int i = 1; i <= 100000; i ++) {
        ans += cal(col[i]) + cal(row[i]);
    }
    cout << ans << endl;
    //======================================

    return 0;   
}

/*DETAILS
    相同颜色的曼哈顿距离总和
*/

D. Integral Array

题意

给定n个数,对于每个x和y(x >= y),都要有x/y在这n个数中出现

思路

枚举每个y的倍数,相当于转换成x = y * k,如果有x和y出现,那么必然需要有k出现,否则就输出"NO"
对于每个x,y的范围是[y * k, y * k + y - 1],才满足x = y * k,用前缀和来确定这个区间内有没有数字即可

代码

void solve(){
    int n, c;
    cin >> n >> c;
    for(int i = 1; i <= c * 2 + 10; i ++) {
        cnt[i] = 0, ct[i] = 0;
    }
    int x;
    for(int i = 1; i <= n; i ++) {
        cin >> x;
        if(!cnt[x]) cnt[x] ++, ct[x] ++;
    }
    for(int i = 1; i <= 2 * c + 10; i ++) {
        cnt[i] += cnt[i - 1];
    }
    bool flag = false;
    for(int i = 1; i <= c; i ++) {
        if(ct[i]) {
            for(int j = 1; j <= c / i; j ++) {
                if(cnt[j * i + i - 1] - cnt[j * i - 1]) {
                    if(!ct[j]) {
                        flag = true;
                        break;
                    }
                }      
            }
        }
    }
    if(flag) {
        cout << "NO" << endl;
    }
    else cout << "YES" << endl;
}
posted @ 2022-03-07 11:49  行舟C  阅读(104)  评论(0)    收藏  举报