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,1、ccc和ddd并根据以下规则构造一个前进方阵:
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=3、a1,1=1a_{1,1}=1a1,1=1、c=2c=2c=2和d=3d=3d=3,那么前进方阵的情况如下:
(1473695811) \begin{pmatrix}1&4&7\\3&6&9\\5&8&11\end{pmatrix} 1354687911
上个月,马克西姆构建了一个前进方阵,并记住了nnn、ccc和ddd的值。最近,他发现了一个由n2n^2n2个整数随机排列而成的数组bbb,并希望确保这些元素就是该特定正方形的元素。
可以证明,对于nnn、a1,1a_{1,1}a1,1、ccc和ddd中的任意值,都存在一个满足所有规则的渐进方格。
分析:
记录给定矩阵中每个数出现次数,选择其中最小值为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艘飞船出发探索海洋深处。这些飞船的编号从111到nnn,依次递增;第iii艘飞船的耐久度为aia_iai。
克拉肯按照特定顺序攻击了船只kkk次。首先,它攻击第一艘飞船,然后是最后一艘,接着又是第一艘,以此类推。
克拉肯的每次攻击都会使飞船的耐久度降低111。当船只的耐久度下降到000时,它就会沉没,不再受到攻击(因此船只不再是第一艘或最后一艘,克拉肯只攻击尚未沉没的船只)。如果所有的船只都沉没了,克拉肯也就没有什么可攻击的了,于是它就游走了。
例如,如果n=4n=4n=4、k=5k=5k=5和a=[1,2,4,3]a=[1,2,4,3]a=[1,2,4,3],就会发生以下情况:
- 克拉肯攻击第一艘飞船,其耐久度变为零,现在为a=[2,4,3]a=[2,4,3]a=[2,4,3];
- 卡拉基攻击最后一艘飞船,现在为a=[2,4,2]a=[2,4,2]a=[2,4,2];
- 克拉肯攻击第一艘飞船,现在为a=[1,4,2]a=[1,4,2]a=[1,4,2];
- 克拉肯号攻击最后一艘飞船,现在是a=[1,4,1]a=[1,4,1]a=[1,4,1];
- 克拉肯攻击第一艘飞船,其耐久度变为零,现在为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个整数组成的数组bbb(m≤nm\le nm≤n)。
如果数组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+11≤l≤n−m+1的元素al,al+1,…,al+m−1a_l,a_{l+1},\dots, a_{l+m-1}al,al+1,…,al+m−1构成了一个好数组。
分析:
本题为滑动窗口,考虑使用双指针,用一个双指针在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 n1≤k≤n),然后任意多次进行以下运算:选择字符串中连续的kkk个字符并将其反转,即用"1"替换所有"0",反之亦然。
通过这些操作,您需要使字符串中的所有字符都等于"1"。
例如,如果是n=5n=5n=5、s=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-1n−1个数字进行游戏。夏娃再次删除一个数字,然后爱丽丝和鲍勃用n−2n-2n−2个数字进行游戏。这个过程一直持续到数字序列为空为止。
夏娃似乎认为在这样的游戏中,爱丽丝几乎总是赢,所以她希望鲍勃赢的次数越多越好。如果夏娃以最佳方式移除数字,求鲍勃能赢爱丽丝的最大次数。
分析:
这个题其实很好想,首先可以想到444只要有那么就一定和1,2,31,2,31,2,3没有任何关系,因为无法组成000,那么就将444的数量单独拿出来看,再看1,2,31,2,31,2,3的数量,可以想到111和222可以和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,赛后大家可以一起交流做题思路,分享做题技巧,欢迎大家的加入。

1281

被折叠的 条评论
为什么被折叠?



