new file: solutions/P7458.md
This commit is contained in:
1 parent
47e9acfb6a
commit
bde443aa2e
1 file changed
+77
@@ -0,0 +1,77 @@
|
|||||||
|
# P7458 [CERC2018] Clockwork ||ange 题解
|
||||||
|
|
||||||
|
## 二进制表示
|
||||||
|
|
||||||
|
我们只关心每个畜栏是否非空,因此可以用一个二进制数表示整个畜栏状态。
|
||||||
|
|
||||||
|
一次搬迁选择正整数 $K$,在二进制表示中,“右边第 $K$ 个畜栏”正好对应右移 $K$ 位。因此一次操作可以写成 $newa = nowa \mid (nowa \gg K)$。其中:
|
||||||
|
|
||||||
|
- $nowa$ 保留原来的非空畜栏。
|
||||||
|
- $nowa \gg K$ 把兔子移动到右边第 $K$ 个畜栏。
|
||||||
|
- 按位或表示合并新旧状态。
|
||||||
|
|
||||||
|
如果某个畜栏离最后一个畜栏太近,右移后越界,越界部分自然消失;而原畜栏仍然保留,所以正好符合题目“太靠右则全部留在原畜栏”的规则。
|
||||||
|
|
||||||
|
## DFS 搜索
|
||||||
|
|
||||||
|
设当前状态为 $nowa$,已经进行了 $now$ 次搬迁,上一次选择的 $K$ 为 $pre_k$。
|
||||||
|
|
||||||
|
由于每次操作都是“并上右移后的结果”,操作顺序实际上可以交换。因此我们可以限制选择的 $K$ 非降,避免重复枚举同一种操作序列。
|
||||||
|
|
||||||
|
其中 $newa > nowa$ 用来剪掉没有产生任何新非空畜栏的操作。因为所有可达状态都包含初始状态 $a$,所以 $newa > nowa$ 等价于“至少新增了一个初始为空的畜栏”。如果一次操作没有新增任何畜栏,它不会帮助达到目标,可以跳过。
|
||||||
|
|
||||||
|
如果:
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
now_a == (1ll << n) - 1
|
||||||
|
```
|
||||||
|
|
||||||
|
说明所有 $n$ 个畜栏都非空,更新答案。
|
||||||
|
|
||||||
|
## 为什么最多只需要 6 次
|
||||||
|
|
||||||
|
如果第一个畜栏有兔子,那么可以依次选择 $K = 1, 2, 4, 8, 16, 32$。
|
||||||
|
|
||||||
|
不难发现,只要第一个畜栏有兔子,六次操作一定可以填满。
|
||||||
|
|
||||||
|
## 参考代码
|
||||||
|
|
||||||
|
::::success[code]
|
||||||
|
|
||||||
|
```cpp
|
||||||
|
#include<bits/stdc++.h>
|
||||||
|
using namespace std;
|
||||||
|
long long a;
|
||||||
|
int minans = INT_MAX;
|
||||||
|
int n;
|
||||||
|
void dfs(int now, int pre_k, long long now_a) {
|
||||||
|
if(now > 6 || now >= minans) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(now_a == (1ll << n) - 1) {
|
||||||
|
minans = min(minans, now);
|
||||||
|
}
|
||||||
|
for(int k = pre_k; k <= n; ++k) {
|
||||||
|
long long new_a = now_a | (now_a >> k);
|
||||||
|
if(new_a > now_a) dfs(now + 1, k, new_a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int main() {
|
||||||
|
char s[45];
|
||||||
|
scanf("%s", s + 1);
|
||||||
|
if(s[1] == '0') {
|
||||||
|
printf("-1\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
n = strlen(s + 1);
|
||||||
|
for(int i = 1; i <= n; ++i) {
|
||||||
|
a *= 2;
|
||||||
|
if(s[i] == '1') a += 1;
|
||||||
|
}
|
||||||
|
dfs(0, 1, a);
|
||||||
|
printf("%d\n", minans);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
::::
|
||||||
Reference in new issue
Block a user