第一次Div. 2破三留念,F1有思路但是Wa4,如果之后懂了会补
交互就算了吧
A. Colour the Flag
题意:
给一个由 “W”、“R”、"." 构成的n×m的二维网格,其中".“可以替换为"W"或"R”。问将所有的"."都替换掉之后,该图能否表示为由 “W”、"R"交替形成的图。
思路:
对于一顶的
n
n
n和
m
m
m,符合条件的方格实际上只有两种,即第一个字母为“W”或“R”:
第一种 | 第二种 |
---|---|
WRWRW | RWRWR |
RWRWR | WRWRW |
WRWRW | RWRWR |
所以只需要判断原图能否表示为两者之中的任意一个即可。
时间复杂度:
O
(
n
m
)
O(nm)
O(nm)
#include<bits/stdc++.h>
using namespace std;
int n, m;
char s[55][55];
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
getchar();
scanf("%s", s[i] + 1);
}
bool q1 = true, q2 = true;
for (int i = 1; i <= n; i++) {
if (!q1)
break;
for (int j = 1; j <= m; j++) {
if (((i + j) % 2 && s[i][j] == 'R') || ((i + j) % 2 == 0 && s[i][j] == 'W')) {
q1 = false;
break;
}
}
}
for (int i = 1; i <= n; i++) {
if (!q2)
break;
for (int j = 1; j <= m; j++) {
if (((i + j) % 2 && s[i][j] == 'W') || ((i + j) % 2 == 0 && s[i][j] == 'R')) {
q2 = false;
break;
}
}
}
if (q1) {
printf("YES\n");
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
if ((i + j) % 2)
printf("W");
else
printf("R");
printf("\n");
}
} else if (q2) {
printf("YES\n");
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++)
if ((i + j) % 2)
printf("R");
else
printf("W");
printf("\n");
}
} else
printf("NO\n");
}
return 0;
}
B. Histogram Ugliness
题意:
给出一个柱状图,柱状图的高度是a1,a2,…,an,其中ai
>
>
> 0,可以进行操作ai=ai−1,
(
1
≤
i
≤
n
)
(1≤i≤n)
(1≤i≤n)。
它定义了一种丑陋分数 (在执行了一些操作之后)为其轮廓的垂直长度和对其执行的操作数的总和。
(如图的红线长度加操作数即为其丑陋分数)
|
|
求所能获得的最小丑陋分数。
思路:
为了方便,我们设a0
=
=
= an+1
=
0
=0
=0。我们发现,当且仅当ai-1
<
<
<ai
>
>
>ai+1
(
1
≤
i
≤
n
)
(1≤i≤n)
(1≤i≤n)时,才能通过将ai
=
m
a
x
(
=max(
=max(ai-1
,
,
,ai+1
)
)
),操作数为
p
=
p=
p=*ai
−
m
a
x
(
-max(
−max(ai-1
,
,
,ai+1
)
)
)的方式将丑陋分数减小
p
p
p。那么我们只需要找出所有这样的极大值点 ai ,然后算出减小的丑陋分数,然后用初始丑陋分数减去即可。
当时没多想,直接从左端点特判到右端点,维护三个点判断各种情况,略微有些繁琐。
时间复杂度:
O
(
n
)
O(n)
O(n)
#include <bits/stdc++.h>
using namespace std;
int n;
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
if (n == 1) {
long long a;
scanf("%lld", &a);
printf("%lld\n", a);
} else if (n == 2) {
long long a, b;
scanf("%lld %lld", &a, &b);
printf("%lld\n", min(a, b) * 2 + max(a, b) - min(a, b));
} else {
long long res = 0, a, b, c;
scanf("%lld %lld", &a, &b);
int q;
//这个q用来标记a->b是相等(==0)还是递增(==1)还是递减(==2)
if (a < b) {
q = 1;
res += a;
} else if (a > b) {
res += a;
a = b;
q = 0;
} else if (a == b) {
q = 0;
res += a;
}
for (int i = 3; i <= n; i++) {
scanf("%lld", &c);
if (c == b) {
if (q == 0) {
continue;
} else if (q == 1) {
res += b - a;
q = 0;
a = b;
} else if (q == 2) {
res += a - b;
q = 0;
a = b;
}
} else if (c > b) {
if (q == 0) {
q = 1;
b = c;
} else if (q == 1) {
res += b - a;
a = b;
b = c;
} else if (q == 2) {
res += a - b;
a = b;
b = c;
q = 1;
}
} else if (c < b) {
if (q == 0) {
q = 2;
b = c;
} else if (q == 1) {
if (a < c) {
res += b - a;
q = 0;
a = c;
b = c;
} else if (a == c) {
res += b - a;
q = 0;
b = a;
} else if (a > c) {
res += b - a;
q = 2;
b = c;
}
} else if (q == 2) {
res += a - b;
a = b;
b = c;
}
}
}
if (q == 0) {
res += b;
} else if (q == 1) {
res += b;
} else if (q == 2) {
res += a;
}
printf("%lld\n", res);
}
}
return 0;
}
C. Little Alawn’s Puzzle
题意:
给出一个
2
×
n
2×n
2×n的数组,每一行都是数字1、2、3、…、n的排列。任意列可以上下交换swap(s[1][i],s[2][i])
(
1
≤
i
≤
n
)
(1≤i≤n)
(1≤i≤n) ,但是要保证同一列或行上没有相同的数字。问一个给定的
s
[
2
]
[
n
]
s[2][n]
s[2][n],求能够表示为多少种不同的符合条件的形式,答案对
m
o
d
=
1
0
9
+
7
mod=10^{9}+7
mod=109+7取模。
思路:
这道题跟AcWing第一场周赛的C题 数字移动 有着异曲同工之妙,首先从样例分析:
2 6 5 1 4 3 7 8
3 8 7 5 1 2 4 6
要反转1列,就必须反转6列;要反转2列,就必须反转8列;要反转3列,就必须反转4、5、7列。到这里思路就很清晰了:
考虑将排列看成一张图,其中点
s
[
1
]
[
i
]
s[1][i]
s[1][i] 向点
s
[
2
]
[
i
]
s[2][i]
s[2][i] 连边。
那么一个排列在图上一定是
m
(
1
≤
m
≤
n
/
2
)
m(1≤m≤n/2)
m(1≤m≤n/2)个环。
对于每个环,都可以选择反转或者不反转,即答案为
2
m
%
m
o
d
2^{m}\%mod
2m%mod。
时间复杂度:
O
(
n
)
O(n)
O(n)
#include<bits/stdc++.h>
using namespace std;
const int N = 1e9 + 7;
int n;
long long qmi(int b) {
int res = 1 % N;
int a = 2;
while (b) {
if (b & 1)
res = (long long)res * a % N;
a = (long long)a * a % N;
b >>= 1;
}
return res;
}
int p[400010];
int s[400010];
int find(int x) {
if (p[x] != x)
p[x] = find(p[x]);
return p[x];
}
int main() {
int t;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
p[i] = i;
scanf("%d", &s[i]);
}
for (int i = 1; i <= n; i++) {
int a;
scanf("%d", &a);
p[find(a)] = find(s[i]);
}
int cnt = 0;
for (int i = 1; i <= n; i++)
if (p[i] == i)
cnt++;
printf("%d\n", qmi(cnt));
}
return 0;
}
如果有什么疑问或者错误的地方可以留言告诉我(骂的轻一点求求了)。