Codeforces Round #821 (Div. 2)

前置废话

下午的 Div.2 还是比较水的,是我想复杂了,前面简单题切的有些慢,也可能是前几分钟还没睡醒吧。。。

写下简要题面吧,要不然都不知道我在说什么


Codeforces Round #821 (Div. 2)

A. Consecutive Sum

题面

给定一个长度为 n 的序列, 最多可以进行以下操作 k 次:

选择 aiajimodk=jmodk)(1i<jn),并将其交换位置。

执行完所有操作后,你必须选择 k 个连续的元素,使这 k 个元素的总和最大。

输入:T(数据组数) n k a1an

题解

对于所有同余的数 (modk)max 之后求和即可。

B. Rule of League

题面

有一个羽毛球锦标赛,有 n 名球员参加。 玩家从 1n 编号。

规则如下:玩家 1 玩家 2 玩游戏,然后获胜者和玩家 3 玩游戏,然后获胜者和玩家 4 玩游戏,以此类推。

因此,进行了 n1 场比赛,最后一场比赛的获胜者成为冠军。

比赛中没有平局。

你想知道冠军的结果。

目前,您只知道以下信息:

每个球员要么赢了 x 场比赛,要么赢了 y 场比赛。

给定 nxy,找出是否有与此信息匹配的结果。

题解

一开始想复杂了,直接上的 exgcd , 其实仔细想想就能发现:如果 xy 都不为零是不满足题意的,直接输出 1 即可。

还有 xy 都为零是也是直接输出 1

剩下的只有一种为零的直接模拟即可。

C. Parity Shuffle Sorting

题面

给定一个包含 n 个非负整数的数组 a。 你可以对其应用以下操作。

选择两个两个数 alar (1l<rn) 。如果 al+ar 是奇数: aral;否则:alar

找到任何最多 n 个操作的序列,使 a 不递减。 可以证明,它总是可能的。 请注意,你不必尽量减少操作次数

题解

多测不清空,爆零两行泪。

观察操作,发现:奇偶性相同,后面的值赋给前面,否则前面的值赋给后面。

注意到加粗的话:意思是 我们可以乱搞了 可以将这些数变成同一个数!

具体来说:判断第一个数的奇偶性,如果是奇数(偶数同理),那么将所有的奇数变成最后一个奇数的值,再将所有偶数变成第一个奇数的值。

Code moo~~
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
#include <set>
using namespace std;
#define int long long
#define re register int
#define pc_ putchar(' ')
#define pc_n putchar('\n')
#define Bessie signed
inline int read() {
int A = 0, FL = 1;
char CH = getchar();
while(CH < '0' || CH > '9') FL = CH == '-' ? -1 : 1, CH = getchar();
while(CH >= '0' && CH <= '9') A = (A << 3) + (A << 1) + (CH ^ '0'), CH = getchar();
return A * FL;
}
inline void ot(int x) {
if(x < 0) putchar('-'), x = -x;
if(x >= 10) ot(x / 10); putchar(x % 10 | '0');
}
const int CTR = 2e5 + 7, INF = 5e5 + 7;
int T;
int n;
int a;
int x[CTR], topx, y[CTR], topy;
Bessie main() {
T = read();
while(T--) {
n = read();
//当时没清空x[1]和y[1]爆了三发
//但是直接memset会T
x[1] = y[1] = topx = topy = 0;
for(re i = 1; i <= n; ++i) {
a = read();
if(a % 2 == 0) x[++topx] = i;
else y[++topy] = i;
}
ot(n - 1),pc_n;
if(n - 1 == 0) continue;
if(x[1] == 1) {
for(re i = 1; i < topx; ++i) ot(x[i]),pc_,ot(x[topx]),pc_n;
for(re i = 1; i <= topy; ++i) ot(1),pc_,ot(y[i]),pc_n;
}
else if(y[1] == 1){
for(re i = 1; i < topy; ++i) ot(y[i]),pc_,ot(y[topy]),pc_n;
for(re i = 1; i <= topx; ++i) ot(1),pc_,ot(x[i]),pc_n;
}
}
return 0;
}

D1. Zero-One (Easy Version)

题面

给定两个 01 字符串 ab,长度均为 n。 你可以多次执行以下操作(可能为零)。

选择两个数 al,ar(l<r)

al 更改为 (1al),并将 ar 更改为 (1ar)

如果 l+1=r ,则操作成本为 x,否则成本为 y

你必须找到使 a 等于 b 所需的最低成本,或者输出1 (a 不可能等于 b)

5n30001yx109

具有启发性的样例

in

4(T)
5(n) 8(x) 7(y)
01001(a)
00101(b)
5 7 2
01000
11011
7 8 3 //就是这组样例启发我们:如果当 x 过于大时,连续花费两个 y 会比只花费一个 x 更优。
0111001
0100001
5 10 1
01100
01100

out

8
-1
6
0

题解

不合法的情况很简单:不同的数的个数是奇数时就不合法。

然后我们记一个数组 C , 当 ai=biCi=0,否则 Ci=1,现在要将 C 的所有数变为零。

假思路:既然选不相邻的更优,那我就双指针扫(一个从前,一个从后),如果不相邻就加 y ,相邻就加 x

hackn=4,x=5,y=3,C=1 1 1 1。我们发现:输出的答案为 8C1 C4 同时变为零,C2 C3同时变为零),但我们可以一眼看穿:答案应该为 6C1 C3 同时变为零,C2 C4同时变为零)。

正解:

如果 C1 的个数大于 2,那么我们是可以做到每次选的数是不相邻的:将这些 1 分成两部分,每次选第一部分的第 12... 个 与第二部分的 12... 个同时变为零,每次选的这两个数一定是隔着 C21 个数的。答案就是 C2×y

否则判断这两个数是否相邻:如果相邻:答案是 min(x,y×2);否则答案就是 y

Code moo~~
#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <map>
#include <vector>
#include <set>
using namespace std;
#define int long long
#define re register int
#define pc_ putchar(' ')
#define pc_n putchar('\n')
#define Bessie signed
inline int read() {
int A = 0, FL = 1;
char CH = getchar();
while(CH < '0' || CH > '9') FL = CH == '-' ? -1 : 1, CH = getchar();
while(CH >= '0' && CH <= '9') A = (A << 3) + (A << 1) + (CH ^ '0'), CH = getchar();
return A * FL;
}
inline void ot(int x) {
if(x < 0) putchar('-'), x = -x;
if(x >= 10) ot(x / 10); putchar(x % 10 | '0');
}
const int CTR = 3e3 + 7, INF = 5e5 + 7;
int T;
int n, x, y;
char a[CTR], b[CTR];
int cnt, ans;
int sum[CTR];
int dp[CTR][CTR];
Bessie main() {
T = read();
while(T--) {
n = read(), x = read(), y = read();
scanf("%s", a + 1);
scanf("%s", b + 1);
ans = cnt = 0;
for(re i = 1; i <= n; ++i) if(a[i] != b[i]) ++cnt;
if(cnt % 2 != 0) {
ot(-1),pc_n;
continue;
}
if(cnt == 2) {
//这原来还写假过:当时没想到不相邻的情况,就直接输出了 min(x, y * 2)
int fl = 0;
for(re i = 2; i <= n; ++i) {
if(a[i] != b[i] && a[i - 1] != b[i - 1]) {
ot(min(2 * y, x)),pc_n;
fl = 1;
break;
}
}
if(fl) continue;
ot(y),pc_n;
continue;
}
else ot(cnt / 2 * y),pc_n;
}
return 0;
}
posted @   Creator_157  阅读(64)  评论(3编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示