「雅礼集训 2017 Day7」蛐蛐国的修墙方案

#6043. 「雅礼集训 2017 Day7」蛐蛐国的修墙方案

Summarize

题目概括征集中~

Solution

CSP-S RP++!

赛前再做几个搜索 / 模拟,为暴力骗分做准备,顺便填一下雅礼集训的坑。

Part1: 暴搜

观察题意得出,第 $i$ 个位置和第 $P_i$ 个位置上,必须填一个左括号和一个右括号。从左向右填写,每次判断是否可以填左 / 右括号即可。

得分 81 pts 。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<bits/stdc++.h>
using namespace std;

int n;
int ans[105];
int p[105];
bool force_right[105];

void dfs(int dep, int cnt) {
if (dep == n + 1) {
for (int i = 1; i <= n; ++i)
putchar('(' + ans[i]);
exit(0);
}
if (cnt < n / 2) {
if (force_right[dep] == 0) {
if (p[dep] < dep) {
if (ans[p[dep]] == 1) {
ans[dep] = 0;
dfs(dep + 1, cnt + 1);
ans[dep] = 0;
}
} else {
force_right[p[dep]] = 1;
dfs(dep + 1, cnt + 1);
force_right[p[dep]] = 0;
}
}
}
if (dep - cnt <= cnt) {
ans[dep] = 1;
dfs(dep + 1, cnt);
ans[dep] = 0;
}
}

int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &p[i]);
dfs(1, 0);
return 0;
}

Part2: 观察性质

将排列 $P$ 视作置换函数,则 $P$ 必定可以分解为若干个长度为偶数的循环。(若不然,必定无解)对于每个循环都只有 2 种填法,即 0,1,0,1… 或 1,0,1,0…。特判长度为 2 的循环,则剩余的循环最多有 $100 / 4 = 25$ 个。复杂度约为 $2^{25}$ 级别。

得分 100 pts。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;

int n, p[105];

vector<int> circ[105];
bool vis[105], ans[105];
int cnt = 0;

bool check() {
int cnt1 = 0, cnt2 = 0;
for (int i = 1; i <= n; ++i) {
cnt1 += (ans[i] == 0), cnt2 += ans[i];
if (cnt1 < cnt2) return 0;
}
return 1;
}

void dfs(int u) {
if (u == cnt + 1) {
if (check()) {
for (int i = 1; i <= n; ++i)
putchar('(' + ans[i]);
exit(0);
}
return;
}
int len = circ[u].size();
if (!(len ^ 2)) {
ans[circ[u][0]] = 0, ans[circ[u][1]] = 1;
dfs(u + 1);
} else {
for (int i = 0; i ^ len; ++i) ans[circ[u][i]] = i & 1;
dfs(u + 1);
for (int i = 0; i ^ len; ++i) ans[circ[u][i]] = !(i & 1);
dfs(u + 1);
}
}

int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%d", &p[i]);
for (int i = 1; i <= n; ++i) {
if (vis[i] == 0) {
cnt += 1;
int cur = i;
do {
circ[cnt].push_back(cur);
vis[cur] = 1;
cur = p[cur];
} while (cur != i);
}
}
dfs(1);
return 0;
}
# 搜索

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×