題目鏈接:2020ICPC沈陽站 D-Journey to Un'Goro
題目大意:
給定一個整數\(n(n\leq 1e5)\)表示一個只由字符\(r\)和\(b\)構成的字符串序列的長度,對於該序列的任意一個子序列,當該子序列中\(r\)的個數為奇數時,則稱該子序列為“滿意”。要求構造一系列這樣的字符串序列使得其中“滿意”的子序列個數最大,輸出最大個數,另外,這樣的序列一般不唯一,題目要求按字典序輸出前\(100\)個構造的序列。
題解:
這里要從序列前綴中\(r\)個數的奇偶性上去考慮。
設\(P_i\)表示長度為\(i\)的字符序列前綴中\(r\)的個數,那么由題意可知子序列\((i, j)\)中\(r\)的個數為\(P_j - P_{i-1}\),當且僅當\(P_j\)與\(P_i-1\)的奇偶性不同時,\(P_j-P_{i-1}\)為奇數。
那么題目就轉化為構造這樣的字符串序列,使得序列\(P_0, P_1, P_2...P_n\)中滿足\(P_i\)和\(P_j\)的奇偶性不同的對數最大,設序列\(P_0, P_1, P_2...P_n\)中奇數個數為\(X\),偶數個數為\(Y\),則滿足\(P_i\)和\(P_j\)的奇偶性不同的對數為\(XY\),很容易想明白\(XY=\lfloor(n+1)/2\rfloor\times\lceil(n+1)/2\rceil\),其實就是\(X\)和\(Y\)各取一半時乘積最大。
而同時發現題目只要求輸出前\(100\)個序列,因此可以搜索+剪枝過掉,在\(dfs\)時分別記錄當前偶數個數\(cnt_0\)和奇數個數\(cnt_1\),當\(max\{cnt_0,cnt_1\}>\lceil(n+1)/2\rceil\)時就剪掉。
#include <iostream>
#include <cstdio>
using namespace std;
int n, cnt, limit;
char S[100010];
void dfs(int k, int cnt0, int cnt1, bool st) {
if (cnt0 > limit || cnt1 > limit) return;
if (k == n) {
printf("%s\n", S);
if (++cnt >= 100) exit(0);
return;
}
S[k] = 'b';
dfs(k + 1, cnt0 + (st ^ 1), cnt1 + st, st);
st ^= 1;
S[k] = 'r';
dfs(k + 1, cnt0 + (st ^ 1), cnt1 + st, st);
}
int main() {
scanf("%d", &n);
long long ans = 1ll * ((n + 1) / 2) * ((n + 2) / 2);
limit = (n + 2) / 2;
printf("%lld\n", ans);
dfs(0, 1, 0, 0);
return 0;
}