2020/2021 ICPC 沈阳站 D题 Journey to Un’Goro (搜索+剪枝)
题目链接: 牛客icpc沈阳站复现赛D-Journey to Un’Goro
题意
给定一个整数n (n <= 1e5) 表示一个只由字符r
和b
构成的字符串序列的长度,对于该序列的任意一个子序列,当该子序列中r
的个数为奇数时,则称该子序列为“满意”。要求构造一系列这样的字符串序列使得其中“满意”的子序列个数最大,输出最大个数,另外,这样的序列一般不唯一,题目要求按字典序输出前100个构造的序列。
分析
这里要从序列前缀中r
个数的奇偶性上去考虑
设
P
i
P_i
Pi表示长度为i的字符序列前缀中r
的个数,那么由题意有子序列 (i, j) 中r
的个数为
P
j
−
P
i
−
1
P_j - P_{i-1}
Pj−Pi−1
当且仅当 P j P_j Pj与 P i − 1 P_i-1 Pi−1的奇偶性不同时, P j − P i − 1 P_j-P_{i-1} Pj−Pi−1为奇数
那么题目就转化为构造这样的字符串序列,使得序列 P 0 , P 1 , P 2 . . . P n P_0, P_1, P_2...P_n P0,P1,P2...Pn中满足 P i P_i Pi和 P j P_j Pj的奇偶性不同的对数最大
(ps:
P
0
=
0
P_0=0
P0=0,这是因为我们假设字符串序列前缀为空时,其中r
的个数为0)
设序列 P 0 , P 1 , P 2 . . . P n P_0, P_1, P_2...P_n P0,P1,P2...Pn中奇数个数为 X X X, 偶数个数为 Y Y Y
则满足 P i P_i Pi和 P j P_j Pj的奇偶性不同的对数为 X Y XY XY
通过一些简单的思考很容易想明白 X Y = ⌊ ( n + 1 ) / 2 ⌋ ⌈ ( n + 1 ) / 2 ⌉ XY = \lfloor(n+1)/2\rfloor\lceil(n+1)/2\rceil XY=⌊(n+1)/2⌋⌈(n+1)/2⌉,其实就是 X X X和 Y Y Y各取一半时乘积最大, ∣ X − Y ∣ ≤ 1 |X-Y|\leq1 ∣X−Y∣≤1
从上式不难看出, X X X和 Y Y Y都不能超过 ⌈ ( n + 1 ) / 2 ⌉ \lceil(n+1)/2\rceil ⌈(n+1)/2⌉,而同时发现题目只要求输出前100个序列,因此可以搜索+剪枝过掉,在dfs时分别记录当前偶数个数 c n t 0 cnt_0 cnt0和奇数个数 c n t 1 cnt_1 cnt1,当 m a x { c n t 0 , c n t 1 } > ⌈ ( n + 1 ) / 2 ⌉ max\{cnt_0,cnt_1\}>\lceil(n+1)/2\rceil max{cnt0,cnt1}>⌈(n+1)/2⌉时就剪掉。
由于我们只需要考虑
P
i
P_i
Pi的奇偶性,因此搜索策略为枚举当前
P
i
P_i
Pi的奇偶性
p
i
∈
{
0
,
1
}
p_i\in\{0, 1\}
pi∈{0,1},0表示偶数,1表示奇数,而又因为只有当前位对应为r
时才能改变
P
i
P_i
Pi的奇偶性,所以当
p
i
=
=
p
i
−
1
p_i == p_{i-1}
pi==pi−1时,字符串序列上的对应位置b
,反之置r
。同时考虑需要按字典序输出,因此优先令
p
i
=
=
p
i
−
1
p_i==p_{i-1}
pi==pi−1
AC代码
#include <bits/stdc++.h>
const int N = 1e5 + 5;
int n, tot, lim;
char S[N];
void dfs(int x, int cnt0, int cnt1, bool st) {
if(cnt0 > lim || cnt1 > lim) return;
if(x == n) {
printf("%s\n", S);
if(++tot >= 100)
exit(0);
return;
}
S[x] = 'b';
dfs(x+1, cnt0 + (st^1), cnt1 + st, st);
st ^= 1;
S[x] = 'r';
dfs(x+1, cnt0 + (st^1), cnt1 + st, st);
}
int main() {
scanf("%d", &n);
long long ans = 1ll * (n + 1)/2 * ((n + 2)/2);
lim = (n+2)/2;
printf("%lld\n", ans);
dfs(0, 1, 0, 0);
return 0;
}