A
题目
我们判断输入的字符串两头是否是两个箭头,再判断中间共 ∣ s ∣ − 2 |s|-2 ∣s∣−2 个字符是否是等号,如果全部是,说明这个字符串是符合条件的,否则,不符合条件。
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 1≤i<j≤n 的条件,先来分析一下以下字符串:
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 ∣S∣−cntk 个字符交换得到新的字符串,其中 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 cntk≥2,就可以将两个 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+l−1 列都是 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 l…1 位变成了 1 1 1。
我们令这一排为 x x x,那么如果这个条件成立:
((x >> (k - 1) & p) == 0)
就表明这一排从 k k k 到 k + l − 1 k +l - 1 k+l−1 列都是 0 0 0 成立。
原理解释:
我们将 x x x 右移了 k − 1 k - 1 k−1 位,这时 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 l…l+k−1 位都是 0 0 0。
而如果我们要把
x
x
x 的
l
…
l
+
k
−
1
l\dots l + k - 1
l…l+k−1 全部赋值为
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;
}