ABC345 A-D 题解

14 篇文章 0 订阅

A

题目

我们判断输入的字符串两头是否是两个箭头,再判断中间共 ∣ s ∣ − 2 |s|-2 s2 个字符是否是等号,如果全部是,说明这个字符串是符合条件的,否则,不符合条件。

AC Code:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
string s;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> s;
	for (int i = 1; i < (int)s.size() - 1; i++) {
		if (s[i] != '=') {
			cout << "No";
			return 0;
		}
	}
	if (s[0] != '<' || s[s.size() - 1] != '>') cout << "No";
	else cout << "Yes";
	return 0;
}

B

题目

由于 c++ 的取整操作是向 0 0 0 取整,所以如果 X X X 为负数时,就不用执行额外的操作,直接输出 X X X 整除 10 10 10 即可。否则,为非负数时,如果 X X X 除以 10 10 10 的余数非零时,说明 X 10 \frac{X}{10} 10X 的小数部分要向整数部分加一个 1 1 1,在 X X X 除以 10 10 10 的商上加一就是正确答案。

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
long long x;

int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> x;
	long long ans = x / 10;
	if (x % 10 && x >= 0) ans++;
	cout << ans;
	return 0;
}

C

题目

题意害人不浅

此题是想让你求出对于一个字串 S S S,交换 S S S 的任意两个字符一次,交换后的不同字符串一共有多少个?

当然,样例 2 2 2 告诉我们,交换后的字串可以和交换前的字串相等。

我们先暂且不管题目中 1 ≤ i < j ≤ n 1\le i < j \le n 1i<jn 的条件,先来分析一下以下字符串:

abcabc

我们先讨论 i i i 1 1 1 的情况:这个时候要被交换的一个字符是 a,我们可以和后面的两个 b 和两个 c 交换,不必和 a 交换,因为这样交换后和之前是一样的,我们先不讨论这种情况。

在讨论 i i i 2 2 2 的情况:为了方便讨论,我们可以让这个字符和前面的字符交换,一共可以和两个 a 和两个 c 交换……

我们发现:对于每一个字符 k k k,这个字符可以和 ∣ S ∣ − c n t k |S|-cnt_k Scntk 个字符交换得到新的字符串,其中 c n t k cnt_k cntk 指字串中 k k k 的数量。对于两个 i i i j j j,其中 S i ≠ S j S_i \neq S_j Si=Sj,我们在讨论 i i i 时交换了 i i i j j j,又在讨论 j j j 时交换了 i i i j j j。所以讨论完后答案要除以 2 2 2

最后,我们还要讨论交换后和以前相等的情况:如果有一个字符 k k k 满足 c n t k ≥ 2 cnt_k \ge 2 cntk2,就可以将两个 k k k 交换得到和之前相等的字串,答案加上 1 1 1

最后输出答案,完结撒花。

时间复杂度: O ( ∣ S ∣ ) O(|S|) O(S)

AC Code:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
string s;
int cnt[30];
long long sum, ans;
int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> s;
	for (int i = (int)s.size() - 1; i >= 0; i--) {
		cnt[(int)(s[i] - 'a')]++;
	}
	for (int i = 0; i < (int)s.size(); i++) {
		ans += (int)s.size() - cnt[(int)(s[i] - 'a')];
	}
	ans /= 2;
	for (int i = 0; i < 26; i++) {
		if (cnt[i] > 1) {
			ans++;
			break;
		}
	}
	cout << ans;
	return 0;
}

D

题目

如果你不知道什么是位运算,请做一个了解。

我们注意到 H , W H,W H,W 很小,只有 10 10 10 N N N 也很小,只有 7 7 7,这给我们提供了搜索的机会。

我们发现,对于每一个可以放置到的情况,如下图:

在这里插入图片描述
如果这种情况合法,那么 ( 3 , 3 ) (3,3) (3,3) 位置必须被放置,那么我们放置下一个方块时,可以直接讨论 ( 3 , 3 ) (3,3) (3,3) 为左上角的情况,因为这个位置无论如何也要被放置。

所以在 DFS 中,我们对于每一个未被放置的矩形,直接讨论左上角第一个未被放置的位置就行了。

对于表示情况,因为 W W W 很小,所以一排的情况可以被表示成一个二进制数,比如上图就可以被表示成这个二进制数组:

00011111
00011111
00011000
00000000
00000000

而我们如果要判断某一排是否从 k k k k + l − 1 k + l - 1 k+l1 列都是 0 0 0,那么先创建一个数,它由 l l l 1 1 1 组成,可以这样写:

int p = (1 << l) - 1

其中我们创建了一个第 l + 1 l+1 l+1 位为 1 1 1,其余位为 0 0 0 的二进制数,再将其减一,那么第 l + 1 l+1 l+1 位变成了 0 0 0,第 l … 1 l\dots1 l1 位变成了 1 1 1

我们令这一排为 x x x,那么如果这个条件成立:

((x >> (k - 1) & p) == 0)

就表明这一排从 k k k k + l − 1 k +l - 1 k+l1 列都是 0 0 0 成立。

原理解释:

我们将 x x x 右移了 k − 1 k - 1 k1 位,这时 x x x 的第一位对应原来的 k k k 位。与 p p p 做按位和后,由于 p p p l + 1 l+1 l+1 位都是 0 0 0,所以只会保留现在 x x x l l l 位,其余位都是 0 0 0,如果这时 x x x 0 0 0,说明 x x x l … l + k − 1 l\dots l + k - 1 ll+k1 位都是 0 0 0

而如果我们要把 x x x l … l + k − 1 l\dots l + k - 1 ll+k1 全部赋值为 1 1 1,就把 p << (k - 1) 异或上原来的 x x x,按位或也可以。

然后把上面的位运算技巧结合起来,再 DFS 一遍,就完结撒花了。

AC Code:

#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cmath>
#include <list>
#include <set>
#include <map>
using namespace std;
int n, h, w;
struct node{
	int a, b;
};
node a[100100];
int vis[100];
bool vis1[10];
void dfs(int dep, int area, int last_x, int last_y) {
	while (last_x <= h) {
		if (((vis[last_x] >> (last_y - 1)) & 1) == 0) {
			break;
		}
		last_y++;
		if (last_y > w) {
			last_y = 1;
			last_x++;
		}
		if (last_x > h) break;
	}
	if (area == h * w) {
		cout << "Yes";
		exit(0);
	}
	if (dep == n + 1) return;
	for (int k = 1; k <= n; k++) {
		if (!vis1[k]) {
			if (a[k].a + last_x - 1 <= h && a[k].b + last_y - 1 <= w) {
				bool flag = 0;
				int tmp = (1 << a[k].b) - 1;
				for (int l = 1; l <= a[k].a; l++) {
					if ((vis[last_x + l - 1] >> (last_y - 1)) & tmp) {
						flag = 1;
						break;
					}
				}
				if (!flag) {
					for (int l = 1; l <= a[k].a; l++) {
						vis[last_x + l - 1] ^= (tmp << (last_y - 1));
					}
					vis1[k] = 1;
					dfs(dep + 1, area + a[k].a * a[k].b, last_x, last_y);
					vis1[k] = 0;
					for (int l = 1; l <= a[k].a; l++) {
						vis[last_x + l - 1] ^= (tmp << (last_y - 1));
					}
				}
			}
			if (a[k].a != a[k].b) {
				swap(a[k].a, a[k].b);
				if (a[k].a + last_x - 1 <= h && a[k].b + last_y - 1 <= w) {
					bool flag = 0;
					int tmp = (1 << a[k].b) - 1;
					for (int l = 1; l <= a[k].a; l++) {
						if ((vis[last_x + l - 1] >> (last_y - 1)) & tmp) {
							flag = 1;
							break;
						}
					}
					if (!flag) {
						for (int l = 1; l <= a[k].a; l++) {
							vis[last_x + l - 1] ^= (tmp << (last_y - 1));
						}
						vis1[k] = 1;
						dfs(dep + 1, area + a[k].a * a[k].b, last_x, last_y);
						vis1[k] = 0;
						for (int l = 1; l <= a[k].a; l++) {
							vis[last_x + l - 1] ^= (tmp << (last_y - 1));
						}
					}
				}
			}
		}
	}
}
int main() {
	srand(time(NULL));
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n >> h >> w;
	for (int i = 1; i <= n; i++) cin >> a[i].a >> a[i].b;
	dfs(1, 0, 1, 1);
	cout << "No";
	return 0;
}
  • 15
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值