二进制

二进制

给定一个长度为 $N$ 的二进制串($01$ 串)以及一个正整数 $K$。

按照从左到右的顺序,依次遍历给定二进制串的 $N-K+1$ 个长度为 $K$ 的子串,并计算每个遍历子串的各位数字之和。

将这 $N-K+1$ 个子串数字和按照子串的遍历顺序进行排列,得到的序列就是给定二进制串的 $\texttt{K-}$子串数字和序列。

注意,所有子串数字和均用十进制表示。

例如,当 $K=4$ 时,二进制串 110010 的 $\texttt{K-}$子串数字和序列为 2 2 1,分析过程如下:

  • 依次遍历 110010 的所有长度为 $4$ 的子串:1100 、1001 、0010
  • 计算每个遍历子串的各位数字之和:$1 + 1 + 0 + 0 = 2$、$1 + 0 + 0 + 1 = 2$、$0 + 0 + 1 + 0 = 1$。
  • 将所有子串数字和按顺序排列,最终得到 2 2 1

现在,给定 $N,K$ 以及一个 $\texttt{K-}$子串数字和序列,请你计算一共有多少个不同的长度为 $N$ 的二进制串可以得到该 $\texttt{K-}$子串数字和序列。

数据保证:至少存在一个长度为 $N$ 的二进制串可以得到该 $\texttt{K-}$子串数字和序列。

由于结果可能很大,你只需要输出对 $10^6+3$ 取模后的结果。

输入格式

第一行包含两个整数 $N,K$。

第二行包含 $N-K+1$ 个整数,表示给定的 $\texttt{K-}$子串数字和序列。

输入保证给定的 $\texttt{K-}$子串数字和序列一定合法,即至少存在一个满足条件的二进制串与之对应。

不难发现,长度为 $K$ 的子串的各位数字之和一定不小于 $0$ 且不大于 $K$。

输出格式

一个整数,表示满足条件的二进制串数量对 $10^6+3$ 取模后的结果。

数据范围

$1 \le K \le N \le 10^6$

输入样例:

7 4
3 2 2 2

输出样例:

3

样例解释

满足条件的二进制串一共有 $3$ 个,分别为 101100111010101110011 。

 

解题思路

  找性质,以样例为例,假设长度为$n$的二进制串用序列$p$来表示,对于相邻的两个数$s_0$和$s_1$有$s_0 = p_0 + p_1 + p_2 + p_3$,$s_1 = p_1 + p_2 + p_3 + p_4$。可以发现只有$p_0$和$p_4$不一样,其他$3$位$p_1$、$p_2$、$p_3$都是一样的,又因为$s_0 = 3$比$s_1 = 2$多$1$,因此必然有$p_0 - p_4 = 1$,又因为$p_i \in \{ 0,1 \}$,那么就有$p_0 = 1$,$p_4 = 0$。继续分析相邻的$s_1$和$s_2$,可以发现只有$p_1$和$p_5$不一样,又因为$s_1 = s_2$,因此必然有$p_1 = p_5$。同理可得$p_2 = p_6$。

  根据分析的结果来看一下可以得到多少个不同的序列$p$,我们只需看第一个长度为$k$的子串(即$s_0$)未确定的数位有多少种选择。此时$p_0$已经确定是$1$了,剩余三位还未确定,又因为$s_0 = 3$,故需要在$p_1$、$p_2$、$p_3$中选择两个位作为$1$,另一个作为$0$,因此就有$C_{3}^{2} = 3$种选择。可以发现当第一个长度为$k$的子串中的每一位确定后,$p$中剩余位也都确定了,这是因为$p_4 = 0$,$p_5 = p_1$,$p_6 = p_2$。故$p$一共有$3$种不同的序列。

  对于一般的情况也是类似的。遍历所有相邻的$s_i$和$s_{i+1}$,那么就会有三种情况:

  1. $s_i = s_{i+1}$:那么就有$p_i = p_{i+k}$。
  2. $s_i > s_{i+1}$:那么就有$p_i = 1$,$p_{i+k} = 0$。
  3. $s_i < s_{i+1}$:那么就有$p_i = 0$,$p_{i+k} = 1$。

  其中对于$s_i = s_{i+1}$的情况,此时$p_i$和$p_{i+k}$可能无法确定选$0$还是$1$,但有可能会被后面的数通过第$2$和第$3$种情况确定出来。比如如果枚举到$s_{i+k}$时有$p_{i+k} = 1$,$p_{i+2k} = 0$,那么就能确定出来$p_i = 1$。对于相等的情况我们用并查集来维护某个集合选$0$还是$1$。

  在确定$p$中某些位置明确选什么数以及哪些位置选相同的数后,统计第一个长度为$k$的子串中明确选择$0$与$1$的位置数量,分别记作$c_0$和$c_1$,因此还需要在$k - c_0 - c_1$个未确定的位中选出$s_0 - c_1$个$1$,那么答案就是$C_{k - c_0 - c_1}^{s_0 - c_1}$。而第一个子串中的位都确定后,$p$中剩余的位也都确定了,直观来理解的话对于任意剩余的位$p_i \ \left(i \in [k, n-1] \right)$,我们可以不断往前推,即考虑$p_{i-k}, p_{i-2k}, \ldots, p_{i \bmod k}$这些位。由于此时$p_{i \bmod k}$确定了,因此可以发现$p_i$始终可以推到已确定值的某个位置。也可以用数学归纳法来证明。

  首先第一个子串已经确定了,假设第$i$个子串确定了,看一下第$i+1$个子串是否确定。根据上面的分析可以确定$p_i$和$p_{i+k}$的取值,由于$p_i$确定了,因此$p_{i+k}$也明确选$0$或$1$,又因为$p_{i+1} \sim p_{i+k-1}$确定了,因此第$i+1$个子串也确定了。同理可以证明如果第$i$个子串的和等于$s_i$,那么第$i+1$个子串的和等于$s_{i+1}$。

  AC代码如下,时间复杂度为$O(n + \log{\text{mod}})$:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1e6 + 10, mod = 1e6 + 3;
 5 
 6 int a[N];
 7 int fa[N], v[N];
 8 
 9 int find(int x) {
10     return fa[x] == x ? fa[x] : fa[x] = find(fa[x]);
11 }
12 
13 int qmi(int a, int k) {
14     int ret = 1;
15     while (k) {
16         if (k & 1) ret = 1ll * ret * a % mod;
17         a = 1ll * a * a % mod;
18         k >>= 1;
19     }
20     return ret;
21 }
22 
23 int C(int a, int b) {
24     int up = 1, down = 1;
25     for (int i = 1, j = a; i <= b; i++, j--) {
26         up = 1ll * up * j % mod;
27         down = 1ll * down * i % mod;
28     }
29     return 1ll * up * qmi(down, mod - 2) % mod;
30 }
31 
32 int main() {
33     int n, m;
34     scanf("%d %d", &n, &m);
35     for (int i = 0; i < n - m + 1; i++) {
36         scanf("%d", a + i);
37     }
38     for (int i = 0; i < n; i++) {
39         fa[i] = i;
40         v[i] = -1;  // -1表示不确定选0还是1
41     }
42     for (int i = 0; i < n - m; i++) {
43         int x = find(i), y = find(i + m);
44         if (a[i] == a[i + 1]) v[y] = v[x], fa[x] = y;   // 这里要把较大的位y并到较小的位x,因为较小的位的v[x]可能确定了选什么,而v[y]=-1,因此应该把y并到x
45         else if (a[i] > a[i + 1]) v[x] = 1, v[y] = 0;
46         else v[x] = 0, v[y] = 1;
47     }
48     int s0 = 0, s1 = 0;
49     for (int i = 0; i < m; i++) {
50         if (v[find(i)] == 0) s0++;
51         else if (v[find(i)] == 1) s1++;
52     }
53     printf("%d", C(m - s0 - s1, a[0] - s1));
54     
55     return 0;
56 }

 

参考资料

  AcWing 5170. 二进制(秋季每日一题2023):https://www.acwing.com/video/4880/

posted @ 2023-08-26 09:50  onlyblues  阅读(18)  评论(0编辑  收藏  举报
Web Analytics