ABC345 A ~ D
ABC345
题外话:巨难。
A
翻译
现在给你一个字符串,定义一个合法的箭头由一个 <
,\(k\) 个 =
,一个 >
组成的长度为 \(k + 2\) 的字符串。问字符串 \(s\) 是否是一个合法的箭头。
思路
赛时因为翻译问题,吃了 \(1\) 发罚时。
只需要判断 \(s_1\) 是否为 <
,\(s_2\sim s_{n-1}\) 是否为 =
,\(s_n\) 是否为 >
即可。
代码
#include <bits/stdc++.h>
#define gt getchar
#define pt putchar
#define ll long long
using namespace std;
const int MAXN = 1e5 + 5;
ll read() {
ll x = 0, f = 1;char ch = gt();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1;ch = gt();}
while (ch >= '0' && ch <= '9') {x *= 10;x += ch - '0';ch = gt();}
return x * f;
}
char s[105];
int main() {
cin >> s + 1;
ll len = strlen(s + 1);
for (int i = 2; i < len; i++) {
if(s[i] != '=') return cout << "No\n", 0;
}
if(s[1] != '<' || s[len] != '>') cout << "No\n";
else cout << "Yes\n";
return 0;
}
B
翻译
给定一个介于 \(-10^{18}\) 和 \(10^{18}\) 之间的数 \(x\),求 \(\lceil\frac{x}{10}\rceil\)。
\(\lceil p \rceil\) 是上取整的意思。
思路
分类讨论。
-
当 \(x \ge 0\) 时
-
如果 \(x\) 是 \(10\) 的倍数,答案是 \(\frac{x}{10}\)。
-
否则,答案是 \(\lfloor \frac{x}{10} \rfloor + 1\)。
-
-
当 \(x < 0\) 时
容易发现答案为 \(\frac{x}{10}\)。
代码
#include <bits/stdc++.h>
#define gt getchar
#define pt putchar
#define ll long long
using namespace std;
const int MAXN = 1e5 + 5;
ll read() {
ll x = 0, f = 1;char ch = gt();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1;ch = gt();}
while (ch >= '0' && ch <= '9') {x *= 10;x += ch - '0';ch = gt();}
return x * f;
}
int main() {
ll t;
cin >> t;
if(t % 10 == 0 || t < 0) cout << t / 10;
else cout << t / 10 + 1;
return 0;
}
C
翻译
给你一个字符串 \(s\)。你可以对这个字符串进行一次操作。
- 设 \(n\) 是 \(s\) 的长度。选择一对整数 \((i,j)(1 \le i \lt j \le n)\),交换 \(s_i, s_j\)。
问有交换出来的字符串有多少个不同的。
思路
暴力会 TLE。
考虑从前往后枚举 \(j\),对于每个 \(1\le i \lt j\),如果 \(s_i \ne s_j\),那么交换 \(i, j\) 就可以获得一个新字符串。
最后,如果 \(s\) 中有任意 \(2\) 个相同的字符,那么交换这两个字符就可以得到原字符串,答案 \(+1\)。
#include <bits/stdc++.h>
#define gt getchar
#define pt putchar
#define ll long long
using namespace std;
const int MAXN = 1e5 + 5;
ll read() {
ll x = 0, f = 1;char ch = gt();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1;ch = gt();}
while (ch >= '0' && ch <= '9') {x *= 10;x += ch - '0';ch = gt();}
return x * f;
}
char s[1000005];
ll num[250];
int main() {
cin >> s;
ll len = strlen(s);
ll res = 0;
num[s[0]]++;
for (int i = 1; i < len; i++) {
res += i - num[s[i]];
num[s[i]]++;
}
for (int i = 'a'; i <= 'z'; i++) {
if(num[i] >= 2) {
++res;
break;
}
}
cout << res << '\n';
return 0;
}
D
翻译
有一个由 \(h\) 行和 \(w\) 列组成的网格,每个单元格的边长为 \(1\) ,我们有 \(n\) 块瓷砖。第 \(i\) 个瓷砖 \((1\leq i\leq N)\) 是一个大小为 \(a_i \times b_i\) 的矩形。
请判断是否有可能在网格上放置瓷砖,从而满足以下所有条件:
- 每个单元格都正好被一个图块覆盖。
- 有未使用的瓷砖也没关系。
- 瓷砖在放置时可以旋转或翻转。但是,每块瓷砖必须与单元格的边缘对齐,不得超出网格。
思路
ABC 经典大模拟。
深度优先搜索,但是和不同深搜不太一样。
每次搜索按照从上到下、从左到右的顺序找到第一个没有铺的网格位置。然后枚举所有剩下没有用过的瓷砖,看看横着放、竖着放怎么能放进去。如果有合法方案往下搜。
看代码吧。
#include <bits/stdc++.h>
#define gt getchar
#define pt putchar
#define ll long long
using namespace std;
const int MAXN = 1e5 + 5;
ll read() {
ll x = 0, f = 1;char ch = gt();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1;ch = gt();}
while (ch >= '0' && ch <= '9') {x *= 10;x += ch - '0';ch = gt();}
return x * f;
}
bool f[15][15];//f[i][j] 表示 (i,j) 有没有铺过
ll n, h, w;
ll a[15], b[15];
bool use[15];//use[i] 表示第 i 块砖是否用过
void dfs() {
ll x = -1, y = -1;
for (int i = 1; i <= h; i++) {
for (int j = 1; j <= w; j++) {
if(!f[i][j]) {
x = i;
y = j;
break;
}
}
if(x != -1) break;
}
if(x == -1 && y == -1) {
//铺满了
cout << "Yes\n";
exit(0);
}
for (int now = 1; now <= n; now++) {
if(use[now]) continue;
//枚举没有用过的格子
for (int p = 1; p <= 2; p++) {
//横着放/竖着放
bool flag = true;
for (int i = 0; i < a[now]; i++) {
for (int j = 0; j < b[now]; j++) {
if(i + x > h || j + y > w || f[i + x][j + y]) {
flag = false;
break;
}
}
if(!flag) break;
}
if(flag) {
//这么铺合法
for (int i = 0; i < a[now]; i++) {
for (int j = 0; j < b[now]; j++) {
f[i + x][j + y] = true;
}
}
use[now] = true;
dfs();
for (int i = 0; i < a[now]; i++) {
for (int j = 0; j < b[now]; j++) {
f[i + x][j + y] = false;
}
}
use[now] = false;
//别忘改回来
}
swap(a[now], b[now]);
}
}
}
int main() {
n = read(), h = read(), w = read();
for (int i = 1; i <= n; i++) {
a[i] = read(), b[i] = read();
}
dfs();
cout << "No\n";
return 0;
}