Codeforces LATOKEN Round 1 (Div. 1 + Div. 2)ABC题解

第一次Div. 2破三留念,F1有思路但是Wa4,如果之后懂了会补
交互就算了吧


A. Colour the Flag

题意
给一个由 “W”、“R”、"." 构成的n×m的二维网格,其中".“可以替换为"W"或"R”。问将所有的"."都替换掉之后,该图能否表示为由 “W”、"R"交替形成的图。
思路
对于一顶的 n n n m m m,符合条件的方格实际上只有两种,即第一个字母为“W”或“R”:

第一种第二种
WRWRWRWRWR
RWRWRWRWRW
WRWRWRWRWR

所以只需要判断原图能否表示为两者之中的任意一个即可。
时间复杂度 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) (1in)
它定义了一种丑陋分数 (在执行了一些操作之后)为其轮廓的垂直长度和对其执行的操作数的总和。
(如图的红线长度加操作数即为其丑陋分数)

求所能获得的最小丑陋分数。
思路
为了方便,我们设a0 = = = an+1 = 0 =0 =0。我们发现,当且仅当ai-1 < < <ai > > >ai+1 ( 1 ≤ i ≤ n ) (1≤i≤n) (1in)时,才能通过将ai = m a x ( =max( =maxai-1 , , ai+1 ) ) ,操作数为 p = p= p=*ai − m a x ( -max( maxai-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) (1in) ,但是要保证同一列或行上没有相同的数字。问一个给定的 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(1mn/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;
}

如果有什么疑问或者错误的地方可以留言告诉我(骂的轻一点求求了)。

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值