1 条题解
-
0
题解:Binaria
题目分析
问题核心
给定一个长度为 (M = N - K + 1) 的 SMS 序列(由二进制字符串的滑动窗口和组成),求可能的原始二进制字符串的数量,结果对 (10^6 + 3) 取模。
关键约束与建模
-
SMS 序列定义:设原始二进制字符串为 (x_1, x_2, ..., x_N)((x_i \in {0,1})),则 SMS 序列的第 (i) 项为: [ s_i = x_i + x_{i+1} + ... + x_{i+K-1} ]
-
相邻项关系:对于任意 (1 \leq i < M),有: [ s_{i+1} = s_i - x_i + x_{i+K} ] 变形得: [ x_{i+K} = s_{i+1} - s_i + x_i ] 该式是核心递推关系,表明 (x_{i+K}) 由 (x_i) 和 SMS 序列的相邻项差值决定。
-
二进制约束:(x_j \in {0,1}),因此由递推式可得:
- (s_{i+1} - s_i) 只能是 (-1, 0, 1)(否则 (x_{i+K}) 无法为 0 或 1)。
- 若 (s_{i+1} - s_i = 1),则 (x_{i+K} = x_i + 1),故 (x_i = 0) 且 (x_{i+K} = 1)。
- 若 (s_{i+1} - s_i = -1),则 (x_{i+K} = x_i - 1),故 (x_i = 1) 且 (x_{i+K} = 0)。
- 若 (s_{i+1} - s_i = 0),则 (x_{i+K} = x_i)(值相同,暂未确定)。
数据范围挑战
- (N \leq 10^6),需设计 (O(N)) 或 (O(K + M)) 复杂度的线性算法,避免嵌套循环。
- 核心难点:利用递推关系将原始字符串按 (K) 个“链”分组,每组独立求解,最终通过组合数计算总方案数。
算法设计
核心思路
- 分组策略:根据递推关系 (x_{i+K} = s_{i+1} - s_i + x_i),原始字符串的第 (j) 位可按 (j \mod K) 分组(共 (K) 组)。例如 (K=4) 时,分组为 ({x_1, x_5, x_9, ...})、({x_2, x_6, x_{10}, ...}) 等。
- 每组内的元素由递推关系关联,独立于其他组,总方案数为各组方案数的乘积。
- 组内约束检查与求解:
- 对每组,根据 SMS 序列的相邻差值,推导组内元素的取值约束(必须为 0 或 1)。
- 若组内存在矛盾(如推导得出某元素既为 0 又为 1),则总方案数为 0。
- 自由变量计数与组合数计算:
- 每组中,若所有元素的取值已被完全确定(无自由变量),则方案数为 1。
- 若存在未确定的自由变量,需结合 SMS 序列的首项 (s_1) 计算合法组合数。
具体步骤
1. 预处理组合数
- 预计算 (10^6 + 3) 模下的阶乘 (fact)、逆元 (inv)、逆阶乘 (inv_fac),用于快速计算组合数 (C(n, k))(表示从 (n) 个元素中选 (k) 个的方案数)。
- 组合数公式: [ C(x, y) = \begin{cases} 0 & x < y \text{ 或 } x < 0 \text{ 或 } y < 0 \ \frac{fact[x]}{fact[y] \cdot fact[x-y]} \mod (10^6 + 3) & \text{否则} \end{cases} ]
2. 分组处理与约束检查
- 对每组 (i)((0 \leq i < K),对应原始字符串的第 (i+1) 位开始的组):
- 遍历组内元素(按 (j = i, i+K, i+2K, ...) 顺序),利用 SMS 序列的相邻差值 (s_{j+1} - s_j) 推导元素取值。
- 若差值为 1 或 -1,组内元素的取值被唯一确定,检查是否满足 0/1 约束;若差值为 0,元素取值与前一个相同(暂未确定)。
- 统计每组中已确定为 0 的元素数 (tot0)、已确定为 1 的元素数 (tot1)。
3. 自由变量与组合数计算
- 首项 (s_1) 是前 (K) 个元素的和,即: [ s_1 = \sum_{i=0}^{K-1} x_{i+1} ]
- 设 (free = K - tot0 - tot1)(未确定的自由变量数,即前 (K) 个元素中未被约束的位数),(fixed1 = tot1)(前 (K) 个元素中已确定为 1 的位数)。则自由变量中需选择 (t = s_1 - fixed1) 个设为 1,剩余设为 0,方案数为 (C(free, t))。
- 若 (t < 0) 或 (t > free),方案数为 0(无合法选择)。
关键细节
- 约束矛盾检查:若组内推导得出某元素取值既为 0 又为 1,或取值超出 0/1 范围,直接输出 0。
- 自由变量的独立性:所有自由变量均在前 (K) 个元素中,且各组的自由变量互不影响,因此总方案数为组合数 (C(free, t))(因各组自由变量的选择需满足 (s_1) 的约束,本质是整体组合,而非各组乘积)。
代码关键模块解析
1. 组合数预处理
int fact[N], inv[N], inv_fac[N]; int C(int x, int y) { return (x < y || x < 0 || y < 0) ? 0 : (1ll * fact[x] * ((1ll * inv_fac[y] * inv_fac[x - y]) % mod)) % mod; } // 预处理阶乘、逆元、逆阶乘 fact[0] = inv_fac[0] = inv[1] = inv_fac[1] = fact[1] = 1; for (int i = 2; i < N; i++) { fact[i] = (1ll * fact[i - 1] * i) % mod; inv[i] = (1ll * inv[mod % i] * (mod - mod / i)) % mod; // 费马小定理求逆元 inv_fac[i] = (1ll * inv_fac[i - 1] * inv[i]) % mod; }- 预处理范围覆盖 (10^6 + 10),满足 (N \leq 10^6) 的需求。
- 逆元计算采用费马小定理,因 (10^6 + 3) 是质数。
2. 分组约束处理
int tot0 = 0, tot1 = 0; for (int i = 0; i < k; i++) { // 遍历 K 个组 bool ok = false; for (int j = i; j + k < n; j += k) { // 组内元素:j, j+k, j+2k,... if (a[j] != a[j + 1]) { // 相邻 SMS 项不同,差值非 0 if (abs(a[j] - a[j + 1]) != 1) { puts("0"); return 0; } // 差值非法 ok = true; // 推导组内元素取值 if (a[j] > a[j + 1]) { b[j] = 1; b[j + k] = 0; } else { b[j] = 0; b[j + k] = 1; } // 向前推导组内前面的元素 for (int x = j - k; x >= i; x -= k) b[x] = b[j]; // 向后推导组内后面的元素 for (int x = j + k; x + k < n; x += k) { if (a[x] == a[x + 1]) b[x + k] = b[x]; else { if (abs(a[x] - a[x + 1]) != 1) { puts("0"); return 0; } if (a[x] > a[x + 1]) b[x + k] = b[x] - 1; else b[x + k] = b[x] + 1; if (b[x + k] < 0 || b[x + k] > 1) { puts("0"); return 0; } // 超出 0/1 范围 } } break; } } if (ok) { // 组内元素已确定 if (b[i]) tot1++; else tot0++; } }- 对每个组,找到第一个相邻 SMS 项不同的位置,以此为起点推导组内所有元素的取值。
- 若组内所有 SMS 项均相同,则组内元素取值相同(自由变量,未计入 (tot0) 或 (tot1))。
3. 组合数计算与结果输出
printf("%d\n", C(k - tot0 - tot1, a[0] - tot1));- (k - tot0 - tot1) 是前 (K) 个元素中的自由变量数。
- (a[0] - tot1) 是自由变量中需设为 1 的个数(满足首项 (s_1) 的和约束)。
- 组合数结果即为总方案数。
时间复杂度与空间复杂度
- 时间复杂度:(O(N + K))。预处理组合数为 (O(N)),分组处理每组元素的总个数为 (N),因此总时间线性。
- 空间复杂度:(O(N))。存储阶乘、逆元、逆阶乘数组,以及输入的 SMS 序列和组内元素取值数组 (b)。
关键结论
- 分组思想:利用递推关系将原始字符串按 (K) 分组,各组独立求解,大幅降低问题复杂度。
- 约束推导:通过 SMS 序列的相邻差值,推导组内元素的取值约束,确保满足二进制条件。
- 组合数应用:自由变量的选择需满足首项和约束,总方案数为组合数 (C(free, t)),体现了“有限制的选择”问题的核心解法。
-
- 1
信息
- ID
- 5437
- 时间
- 1000ms
- 内存
- 1024MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者