Codeforces Round 938 (Div. 3) A~F

A.Yogurt Sale(贪心)

题意:

在"Vosmiorochka"商店里,一份酸奶的价格是aaa布尔,但现在有促销活动,可以用bbb布尔买到两份酸奶。

马克西姆正好需要购买nnn份酸奶。在购买两份酸奶时,他可以选择以正常价格或促销价格购买。

马克西姆购买nnn份酸奶至少需要花费多少布尔?

分析:

两种买法,哪种最省就用哪种买,特判一下奇数情况即可。

代码:

#include<bits/stdc++.h>

using namespace std;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, a, b;
        cin >> n >> a >> b;
        if (b >= 2 * a) {
            cout << n * a << endl;
        } else {
            int k = n / 2;
            int r = n % 2;
            cout << k * b + r * a << endl;
        }
    }
    return 0;
}

B.Progressive Square(枚举)

题意:

大小为nnn的前进方阵是一个n×nn\times nn×n的矩阵。马克西姆选择三个整数a1,1a_{1,1}a1,1cccddd并根据以下规则构造一个前进方阵:

ai+1,j=ai,j+c a_{i+1,j}=a_{i,j}+c ai+1,j=ai,j+c

ai,j+1=ai,j+d a_{i,j+1}=a_{i,j}+d ai,j+1=ai,j+d

例如,如果n=3n=3n=3a1,1=1a_{1,1}=1a1,1=1c=2c=2c=2d=3d=3d=3,那么前进方阵的情况如下:

(1473695811) \begin{pmatrix}1&4&7\\3&6&9\\5&8&11\end{pmatrix} 1354687911

上个月,马克西姆构建了一个前进方阵,并记住了nnncccddd的值。最近,他发现了一个由n2n^2n2个整数随机排列而成的数组bbb,并希望确保这些元素就是该特定正方形的元素。

可以证明,对于nnna1,1a_{1,1}a1,1cccddd中的任意值,都存在一个满足所有规则的渐进方格。

分析:

记录给定矩阵中每个数出现次数,选择其中最小值为a1,1a_{1,1}a1,1,构造出合法矩阵的唯一形态并检查每个数出现次数是否合法即可。

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;
map<LL, int> cnt;
vector<int> b;

int main() {
    int t;
    cin >> t;
    while (t--) {
        int n, c, d;
        cin >> n >> c >> d;
        cnt.clear();
        b.clear();
        for (int i = 1; i <= n * n; i++) {
            int x;
            cin >> x;
            cnt[x] = cnt[x] + 1;
            b.push_back(x);
        }
        sort(b.begin(), b.end());
        int a11 = b[0], flag = 1;
        for (int i = 1; i <= n; ++i) {
            for (int j = 1; j <= n; ++j) {
                LL x = a11 + 1ll * (i - 1) * c + 1ll * (j - 1) * d;
                if (!cnt.count(x) || cnt[x] == 0) flag = 0;
                cnt[x] = cnt[x] - 1;
            }
        }
        cout << (flag ? "YES" : "NO") << endl;
    }
    return 0;
}

C.Inhabitant of the Deep Sea(模拟)

题意:

nnn艘飞船出发探索海洋深处。这些飞船的编号从111nnn,依次递增;第iii艘飞船的耐久度为aia_iai

克拉肯按照特定顺序攻击了船只kkk次。首先,它攻击第一艘飞船,然后是最后一艘,接着又是第一艘,以此类推。

克拉肯的每次攻击都会使飞船的耐久度降低111。当船只的耐久度下降到000时,它就会沉没,不再受到攻击(因此船只不再是第一艘或最后一艘,克拉肯只攻击尚未沉没的船只)。如果所有的船只都沉没了,克拉肯也就没有什么可攻击的了,于是它就游走了。

例如,如果n=4n=4n=4k=5k=5k=5a=[1,2,4,3]a=[1,2,4,3]a=[1,2,4,3],就会发生以下情况:

  1. 克拉肯攻击第一艘飞船,其耐久度变为零,现在为a=[2,4,3]a=[2,4,3]a=[2,4,3]
  2. 卡拉基攻击最后一艘飞船,现在为a=[2,4,2]a=[2,4,2]a=[2,4,2]
  3. 克拉肯攻击第一艘飞船,现在为a=[1,4,2]a=[1,4,2]a=[1,4,2]
  4. 克拉肯号攻击最后一艘飞船,现在是a=[1,4,1]a=[1,4,1]a=[1,4,1]
  5. 克拉肯攻击第一艘飞船,其耐久度变为零,现在为a=[4,1]a=[4,1]a=[4,1]

克拉肯攻击后有多少艘船被击沉?

分析:

kkk分解成两部分,然后两边往中间暴力枚举删数,即每次将左右两端血量较少的一个消灭即可。

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;
const LL N = 1e6 + 7;

LL t, n, k, a[N];

void solve() {
    cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
    }
    LL l = (k + 2 - 1) / 2;
    LL r = k / 2;
    LL rt = 1;
    LL ans = 0;
    while (l != 0) {
        if (rt > n) {
            break;
        }
        if (l - a[rt] >= 0) {
            l -= a[rt];
            ans++;
            a[rt] = 0;
            rt++;
        } else {
            a[rt] -= l;
            l = 0;
            break;
        }
    }
    rt = n;
    while (r != 0) {
        if (rt < 1) {
            break;
        }
        if (a[rt] == 0) {
            break;
        }
        if (r - a[rt] >= 0) {
            r -= a[rt];
            ans++;
            a[rt] = 0;
            rt--;
        } else {
            a[rt] -= r;
            r = 0;
            break;
        }
    }
    cout << ans << endl;
}

int main() {
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

D.Inaccurate Subsequence Search(双指针)

题意:

马克西姆有一个由nnn个整数组成的数组aaa和一个由mmm个整数组成的数组bbbm≤nm\le nmn)。

如果数组ccc中的元素可以重新排列,使其中至少kkk个元素与数组bbb中的元素匹配,那么他认为长度为mmm的数组ccc是好数组。

例如,如果b=[1,2,3,4]b=[1,2,3,4]b=[1,2,3,4]k=3k=3k=3,那么数组[4,1,2,3][4,1,2,3][4,1,2,3][2,3,4,5][2,3,4,5][2,3,4,5]就是好数组(它们可以重新排列如下:[1,2,3,4][1,2,3,4][1,2,3,4][5,2,3,4][5,2,3,4][5,2,3,4]),而数组[3,4,5,6][3,4,5,6][3,4,5,6][3,4,3,4][3,4,3,4][3,4,3,4]则不是好数组。

马克西姆希望选择数组aaa长度为mmm的每个子段作为数组ccc的元素。帮助他计算有多少个子段是好的。

换句话说,找出有多少个位置1≤l≤n−m+11\le l\le n-m+11lnm+1的元素al,al+1,…,al+m−1a_l,a_{l+1},\dots, a_{l+m-1}al,al+1,,al+m1构成了一个好数组。

分析:

本题为滑动窗口,考虑使用双指针,用一个双指针在aaa数组中维护一个长度为mmm区间,同时维护当中与bbb数组中匹配的数量cntcntcnt,使用遍历进行维护肯定不行,但可以发现一个性质,就是随着区间移动,他只有首位的数字发生变化,所以我们只需要判断首位的数字匹配情况,来更新cntcntcnt即可。

代码:

#include<bits/stdc++.h>

using namespace std;
const int N = 2e5 + 5;

int arr[N], brr[N];

void solve() {
    int n, m, k;
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i++) {
        cin >> arr[i];
    }
    map<int, int> mp;
    for (int i = 1; i <= m; i++) {
        cin >> brr[i];
        mp[brr[i]]++;
    }
    map<int, int> temp;

    int res = 0;
    int cnt = 0;

    for (int r = 1, l = 1; r <= n; r++) {
        temp[arr[r]]++;
        if (temp[arr[r]] <= mp[arr[r]])
            cnt++;
        if (r > m) {
            temp[arr[l]]--;
            if (temp[arr[l]] < mp[arr[l]])
                cnt--;
            l++;
        }
        if (r >= m && cnt >= k)
            res++;
    }
    cout << res << endl;
}


int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

E.Long Inversions(差分)

题意:

给出长度为nnn的二进制字符串sss。二进制字符串是仅由字符"1"和"0"组成的字符串。

可以选择一个整数kkk(1≤k≤n1\le k\le n1kn),然后任意多次进行以下运算:选择字符串中连续的kkk个字符并将其反转,即用"1"替换所有"0",反之亦然。

通过这些操作,您需要使字符串中的所有字符都等于"1"。

例如,如果是n=5n=5n=5s=00100s=00100s=00100,则可以选择k=3k=3k=3,并按以下步骤操作:

  • 选择从第111到第333个字符的子串,得到s=11000s=\color{blue}{110}00s=11000
  • 选择从第333到第555个字符的子串,得到s=11111s=11\color{blue}{111}s=11111

kkk的最大值,在这个值上,可以通过所述的操作使字符串中的所有字符都等于"1"。请注意,实现这一目标所需的操作次数并不重要。

分析:

从左到右贪心,例如101110110111011011101这个样例,设k=4k=4k=4,如果只对某一位取反,必然会影响到第i+ki+ki+k位的数,在kkk等于444时,是否该取反的状态如下:

111到第444个数:010001000100

555到第777个数:010010010

此时按位异或,会发现他们均为000

对样例010001001000100100010,取k=4k=4k=4时,取反状态如下:
[1 4]:1011[1~4]:1011[1 4]1011 [5 7]:101[5~7]:101[5 7]101

按位异或不全为000,故kkk不可能取444;取k=3k=3k=3时,有:

[1 3]:101[1~3]:101[1 3]101 [4 6]:110[4~6]:110[4 6]110 [7 7]:1[7~7]:1[7 7]1

按位异或全为111,其一种推导路径如下:

010001001000100100010 011111001111100111110 100111010011101001110 100100110010011001001 111000111100011110001 111111111111111111111

因此只需要开个差分数组,暴力从大到小枚举kkk,找到使差分数组值全相等时的情况输出即可。

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;

LL k;
string s;

void solve() {
    cin >> k;
    cin >> s;
    do {
        vector<int> a(k);
        for (int i = 0; i <= s.length() - 1; i++)
            a[i % k] ^= '1' - s[i];
        if (a == vector<int>(k, a[0])) {
            cout << k << endl;
            return;
        }
    } while (k--);
}

int main() {
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}

F.Unfair Game(思维)

题意:

爱丽丝和鲍勃在傍晚时分聚集在一起,就一个由nnn个整数组成的数列玩一个刺激的游戏,数列中的每个整数都不超过444}。游戏规则太复杂,无法描述,所以我们只描述获胜条件–如果序列中所有数字的按位异或都非零,则爱丽丝获胜;否则,鲍勃获胜。

他们邀请夏娃担任裁判。一开始,爱丽丝和鲍勃用nnn个数字进行游戏。一局游戏结束后,夏娃从序列中移除一个数字,然后爱丽丝和鲍勃用n−1n-1n1个数字进行游戏。夏娃再次删除一个数字,然后爱丽丝和鲍勃用n−2n-2n2个数字进行游戏。这个过程一直持续到数字序列为空为止。

夏娃似乎认为在这样的游戏中,爱丽丝几乎总是赢,所以她希望鲍勃赢的次数越多越好。如果夏娃以最佳方式移除数字,求鲍勃能赢爱丽丝的最大次数。

分析:

这个题其实很好想,首先可以想到444只要有那么就一定和1,2,31,2,31,2,3没有任何关系,因为无法组成000,那么就将444的数量单独拿出来看,再看1,2,31,2,31,2,3的数量,可以想到111222可以和333抵消掉,然后就可以想出一种方法,就是将1,2,31,2,31,2,3的数量取minminmin,然后加上444的数量除以222,是一种情况,再看如果说每个的数字是偶数的话,那么很明显比1,2,31,2,31,2,3抵消要更优,因为每个数字是偶数,如果说是第一种情况最多是222,但是第二种情况每次减222的话答案可以增加333。最后就是特殊的情况,比如1,2,31,2,31,2,3的数量一样,并且全是奇数,那么答案要加111。如果说三个数字都是奇数,那么答案也要加111

代码:

#include<bits/stdc++.h>

typedef long long LL;
using namespace std;

void solve() {
    LL a, b, c, d;
    cin >> a >> b >> c >> d;
    bool f = 0;
    if ((a == b && b == c && a % 2 == 1) || ((a % 2 == 1) && (b % 2 == 1) && (c % 2 == 1))) {
        f = 1;
    }
    LL res = (min(min(a, b), c) + d / 2);
    LL Res = (a / 2) + (b / 2) + (c / 2) + (d / 2) + ((f == 1) ? 1 : 0);
    cout << max(res, Res) << endl;
}

int main() {
    int t;
    cin >> t;
    while (t--) {
        solve();
    }
    return 0;
}

赛后交流

在比赛结束后,会在交流群中给出比赛题解,同学们可以在赛后查看题解进行补题。

群号: 704572101,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

### Codeforces Round 927 Div. 3 比赛详情 Codeforces是一个面向全球程序员的比赛平台,定期举办不同级别的编程竞赛。Div. 3系列比赛专为评级较低的选手设计,旨在提供更简单的问题让新手能够参与并提升技能[^1]。 #### 参赛规则概述 这类赛事通常允许单人参加,在规定时间内解决尽可能多的问题来获得分数。评分机制基于解决问题的速度以及提交答案的成功率。比赛中可能会有预测试案例用于即时反馈,而最终得分取决于系统测试的结果。此外,还存在反作弊措施以确保公平竞争环境。 ### 题目解析:Moving Platforms (G) 在这道题中,给定一系列移动平台的位置和速度向量,询问某时刻这些平台是否会形成一条连续路径使得可以从最左端到达最右端。此问题涉及到几何学中的线段交集判断和平面直角坐标系内的相对运动分析。 为了处理这个问题,可以采用如下方法: - **输入数据结构化**:读取所有平台的数据,并将其存储在一个合适的数据结构里以便后续操作。 - **时间轴离散化**:考虑到浮点数精度误差可能导致计算错误,应该把整个过程划分成若干个小的时间间隔来进行模拟仿真。 - **碰撞检测算法实现**:编写函数用来判定任意两个矩形之间是否存在重叠区域;当发现新的连接关系时更新可达性矩阵。 - **连通分量查找技术应用**:利用图论知识快速求解当前状态下哪些节点属于同一个集合内——即能否通过其他成员间接相连。 最后输出结果前记得考虑边界条件! ```cpp // 假设已经定义好了必要的类和辅助功能... bool canReachEnd(vector<Platform>& platforms, double endTime){ // 初始化工作... for(double currentTime = startTime; currentTime <= endTime ;currentTime += deltaT){ updatePositions(platforms, currentTime); buildAdjacencyMatrix(platforms); if(isConnected(startNode,endNode)){ return true; } } return false; } ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值