2024-10-30-ABC377

A - Rearranging ABC

题意

给定三个字母的字符串,问是不是由ABC构成的。

解法

排个序判断一下即可。

#include <bits/stdc++.h>
using namespace std;
int main() {
	string s;
	cin >> s;
	sort(s.begin(), s.end());
	if (s == "ABC")
		cout << "Yes" << '\n';
	else
		cout << "No" << '\n';
	return 0;
}

B - Avoid Rook Attack

题意

国际象棋,给定一个棋盘,其中#表示车,可以上下左右随便走,问有多少个位置不会被车给覆盖。

解法

用两个数组标记一下哪些行和列被车覆盖了,然后跑一遍每个格子判断一下是否没被行列覆盖。

#include <bits/stdc++.h>
using namespace std;
bool r[8], c[8] ;
int main() {
	for (int i = 0; i < 8; i++) {
		string S;
		cin >> S;

		for (int j = 0; j < 8; j++) {
			if (S[j] == '#') {
				r[i] = true;
				c[j] = true;
			}
		}
	}
	int ans = 0;
	for (int i = 0; i < 8; i++)
		for (int j = 0; j < 8; j++)
			if (!r[i] && !c[j])
				ans++;
	cout << ans << "\n";

	return 0;
}

C - Avoid Knight Attack

题意

国际象棋,给定一个棋盘,其中#表示马,马走日,问有多少个位置不会被马给覆盖。

解法

用map记录一下被覆盖的点,在N*M里一个一个减就行了

#include <bits/stdc++.h>
using namespace std;
int dx[] = {0, 2, 1, -1, -2, -2, -1, 1, 2};
int dy[] = {0, 1, 2, 2, 1, -1, -2, -2, -1};
//八个方向
int main() {
	int N, M;
	cin >> N >> M;
	map<pair<int,int>,bool> s;
	long long ans = 1LL * N * N;
	for (int i = 0; i < M; i++) {
		int a, b;
		cin >> a >> b;
		for (int k = 0; k < 9; k++) {
			int x = a + dx[k];
			int y = b + dy[k];
			if (1 <= x && x <= N && 1 <= y && y <= N && !s.count({x, y})) {
                //不能越界并且以前没有被覆盖过
				ans--;
				s[{x, y}]=1;
			}
		}
	}
	cout << ans << "\n";
	return 0;
}

D - Many Segments 2

题意

给很多对(L,R),请你求在M范围内有多少对(l,r)使其没有包含任何一对(L,R)

2 4
1 2
3 4
5

解法

发现:如果(l,r)是没有包含任何一对(L,R)的,那么(l+1,r)肯定也是满足条件的

那么题目就可以转化成,对于一个固定的r,合法的l的有多少个,也就是求一个离当前r最远的l在哪,然后这之间的一共(r-l+1)个l都是合法的。

我们假设现在已经知道了r-1最远的l在哪,设为l'

image-20241029232410819

那么l'到r想要包含L,R,唯一的可能性就是有L,R的R刚好为r,注意有可能有很多对满足条件的(L,R),那么新的r配对的l应该是最大的L+1,即l=max(l',Lmax+1)

所以我们先计算一下对于每个R最大的L+1在哪里,然后从前往后递推一遍每个r的l即可。

#include <bits/stdc++.h>
using namespace std;
int maxL[200005];
int l[200005];
int main() {
	int N, M;
	cin >> N >> M;
	//计算每一个R最近的L在哪里
	for (int i = 0; i < N; i++) {
		int L, R;
		cin >> L >> R;
		maxL[R] = max(maxL[R], L + 1);
	}
	//计算每一个r最远的合法l在哪里
	l[0]=1;//注意初始化
	for (int i = 1; i <= M; i++) {
		l[i] = max(l[i - 1], maxL[i]);
	}

	long long ans = 0;
	for (int i = 1; i <= M; i++) {
		ans += i - l[i] + 1;
	}
	cout << ans << "\n";

	return 0;
}

E - Permute K times 2

题意

给定一个排列pi(排列指其中的数是由1~n构成的),一共进行k此操作,每次操作将pi替换成ppi,问操作之后的排列。

6 3
5 6 3 1 2 4

解法

遇到排列可以立即考虑建图,i->pi(其他建法也可以,比如pi->ppi,通常表示数字的下一个数字是谁),建图后这个排列应该是由若干个环组成。

然后就可以对着样例尝试:

5 6 3 1 2 4
2 4 3 5 6 1 一步
4 5 3 6 1 2 二步
6 1 3 2 4 5 三步

image-20241030002141531

接下来就是找规律,对于每一个位置,我们看它上面数字怎样变化的,

先看一步的情况:

1号位上的数一步后变成了2
2号位上的数一步后变成了4
3号位上的数一步后变成了3
4号位上的数一步后变成了5
5号位上的数一步后变成了6
6号位上的数一步后变成了1

进图看,不难发现,每个位置往后走2步就是他们的数,

再同样观察二步、三步的情况,会发现分别是向后走4步、8步,最后可以得出其实就是走2^k步的结论

所以解法就是把环处理出来,设环的大小为sz,那么每个位置上的数就是用快速幂算出\(2^k mod sz\)之后的数是谁就行。

#include <bits/stdc++.h>
using namespace std;

//快速幂,计算a的b次方模p
int power(int a, long long b, int p) {
	int res = 1;
	for (; b; b /= 2, a = 1LL * a * a % p) {
		if (b & 1) {
			res = 1LL * res * a % p;
		}
	}
	return res;
}

int main() {
	int N;
	long long K;
	cin >> N >> K;
	
	vector<int> P(N);
	for (int i = 0; i < N; i++) {
		cin >> P[i];
		P[i]--;
	}
	
	vector<bool> vis(N);
	for (int i = 0; i < N; i++) {
		if (vis[i]) {
			continue;
		}
		
		int j = i;
		vector<int> a;
		while (!vis[j]) {
			vis[j] = true;
			a.push_back(j);
			j = P[j];
		}
		
		long long d = power(2, K, a.size());
		for (int x = 0; x < a.size(); x++) {
			P[a[x]] = a[(x + d) % a.size()];
		}
	}
	for (int i = 0; i < N; i++) {
		cout << P[i] + 1 << " \n"[i == N - 1];
	}
	
	return 0;
}
posted @ 2024-11-30 23:27  ~清渠~  阅读(1)  评论(0编辑  收藏  举报