Codeforces Round 632 (Div.2) Solution (Problem A ~ Problem D)

比较毒瘤的一场。但据说 F 是个智障题?做 D 选手大失败…


Problem A

题意

定义邻居指矩阵中上下左右相邻的格子。

要求构造一个由 B 和 W 组成的 $n\times m$ 矩阵,使得矩阵中有 W 邻居的 B 数量 $=$ 有 B 邻居的 W 数量 $+1$。

$2 \leq n,m \leq 100$

做法

在左上角留下一个 W,其它全部填 B 即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# include <bits/stdc++.h>
# define rr register
const int N=100010,INF=0x3f3f3f3f;
inline int read(void){
int res,f=1;
char c;
while((c=getchar())<'0'||c>'9')
if(c=='-')f=-1;
res=c-48;
while((c=getchar())>='0'&&c<='9')
res=res*10+c-48;
return res*f;
}
int main(void){
int T=read();
while(T--){
int n=read(),m=read();
for(rr int i=1;i<=n;++i){
for(rr int j=1;j<=m;++j){
if(i==1&&j==1){
putchar('W');
}else{
putchar('B');
}
}
puts("");
}
}
return 0;
}

Problem B

题意

给定数组 $a_1,a_2,…,a_n$, 和数组 $b_1,b_2,…,b_n$。每次可以选择 $i,j(i<j)$,并把 $a_j$ 变成 $a_i+a_j$。问经过若干次操作后是否可能变成数组 $b$。

$1 \leq n \leq 10^5,a_i\in \{-1,0,1\},-10^9 \leq b_i \leq 10^9$

做法

从前往后扫一遍,看 $b_i$ 是否可以被前面的某个 $a_j$ 经过若干次操作后得到。

$b_i$ 能够被前面的某个 $a_j$ 经过若干次操作后得到,当且仅当以下条件中至少满足一个:

  • $b_i=a_i$

  • $b_i<a_i$,且存在 $j<i$ 满足 $a_j=1$

  • $b_i>a_i$,且存在 $j<i$ 满足 $a_j=-1$
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# include <bits/stdc++.h>
# define rr register
# define int long long
const int N=100010,INF=0x3f3f3f3f;
int T;
int a[N],b[N];
int n;
bool d[10];
inline int read(void){
int res,f=1;
char c;
while((c=getchar())<'0'||c>'9')
if(c=='-')f=-1;
res=c-48;
while((c=getchar())>='0'&&c<='9')
res=res*10+c-48;
return res*f;
}
signed main(void){
T=read();
while(T--){
n=read();
for(rr int i=1;i<=n;++i){
a[i]=read();
}
for(rr int i=1;i<=n;++i){
b[i]=read();
}
d[1]=0,d[2]=0;
if(a[1]!=b[1]){
puts("NO");
continue;
}
for(rr int i=1;i<=n;++i){
if((a[i]==b[i])||(a[i]<b[i]&&d[1])||(a[i]>b[i]&&d[2])){
if(a[i]==-1)
d[2]=true;
if(a[i]==1)
d[1]=true;
}else{
puts("NO");
goto End;
}
}
puts("YES");
End:;
}
return 0;
}

Problem C

题意

给定数组 $a_1,a_2,…,a_n$。

定义 $a$ 的一个连续子数组是 good subarray,当且仅当这个子数组的任何一个连续子数组之和都不为 $0$。

求出 $a$ 数组中 good subarray 的数量。

$1 \leq n \leq 2\cdot 10^5,-10^9 \leq a_i \leq 10^9$

做法

考虑从 $1$ 到 $n$ 依次考虑以 $i$ 结尾的 good subarray 的数量。

如果存在一个 $j$,并且有以它开头的并且在一个 $\leq i$ 位置结尾的 bad subarray(与 good subarray 相对),那么很显然,$\leq j$ 的位置都不可能成为以 $i$ 结尾的 good subarray 的开头。

所以扫过去,顺便维护下最大的 $j$ 就行了。 std::map 瞎搞搞就好。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# include <bits/stdc++.h>
# define rr register
# define int long long
const int N=200010,INF=0x3f3f3f3f;
std::map <int,int> Map;
int a[N];
int n;
int ans=0;
int sum[N];
inline int read(void){
int res,f=1;
char c;
while((c=getchar())<'0'||c>'9')
if(c=='-')f=-1;
res=c-48;
while((c=getchar())>='0'&&c<='9')
res=res*10+c-48;
return res*f;
}
signed main(void){
n=read();
for(rr int i=1;i<=n;++i){
a[i]=read();
}
int last=0;
Map[0]=1;
for(rr int i=1;i<=n;++i){
if(a[i])
++ans;
sum[i]=sum[i-1]+a[i];
last=std::max(last,Map[sum[i]]);
ans+=std::max(0ll,(i-1)-last);
Map[sum[i]]=i+1;
}
printf("%I64d",ans);
return 0;
}

Problem D

题意

给定一个长度为 $n$ 的字符串,由 L 和 R 组成。你可以执行 $k$ 次操作。每次操作时,你可以选择任意对相邻的 RL,把它们改成 LR

如果无法选择至少一对 RL,那么操作结束。

你需要给出一个操作顺序,使得正好 $k$ 次操作后操作结束。

如果无法操作,输出 $-1$。

$n \leq 3000,k \leq 3 \cdot 10^6$

做法

显然,最小的操作次数是在每次操作时选择尽可能多的对。

显然,最大的操作次数是在最小的操作次数基础上,将所有选择的对拆开来操作。

显然,如果最小的操作次数 $>k$,或者最大的操作次数 $<k$,那么只能输出 $-1$。

输出照着 Codeforces 1329 A 就好了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# include <bits/stdc++.h>
# define rr register
const int N=3010,INF=0x3f3f3f3f;
std::vector <int> p[N];
int n,k;
char s[N];
int m;
int cnt;
inline int read(void){
int res,f=1;
char c;
while((c=getchar())<'0'||c>'9')
if(c=='-')f=-1;
res=c-48;
while((c=getchar())>='0'&&c<='9')
res=res*10+c-48;
return res*f;
}
int main(void){
n=read(),k=read();
scanf("%s",s+1);
for(rr int i=1;i<=n;++i){
bool flag=false;
for(rr int j=1;j<=n-1;++j){
if(s[j]=='R'&&s[j+1]=='L'){
p[i].push_back(j);
std::swap(s[j],s[j+1]);
flag=true;
++cnt;
++j;
}
}
if(!flag){
m=i-1;
break;
}
}
if(cnt<k||m>k){
printf("-1");
return 0;
}
int ret=cnt-k;
for(rr int i=1;i<=m;++i){
if(ret>=(p[i].size()-1)){
printf("%d ",p[i].size());
for(rr int j=0;j<p[i].size();++j){
printf("%d ",p[i][j]);
}
puts("");
ret-=(p[i].size()-1);
}else{
if(ret){
printf("%d ",ret+1);
for(rr int j=0;j<=ret;++j){
printf("%d ",p[i][j]);
}
puts("");
for(rr int j=ret+1;j<p[i].size();++j){
printf("1 %d\n",p[i][j]);
}
ret=0;
}else{
for(rr int j=0;j<p[i].size();++j){
printf("1 %d\n",p[i][j]);
}
}
}
}
return 0;
}