首页 > 其他分享 >二进制

二进制

时间:2023-08-26 10:01:54浏览次数:29  
标签:子串 数字 二进制 int 确定 序列

二进制

给定一个长度为 $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$ 个,分别为 1011001,1101010,1110011 。

 

解题思路

  找性质,以样例为例,假设长度为$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/

标签:子串,数字,二进制,int,确定,序列
From: https://www.cnblogs.com/onlyblues/p/17658377.html

相关文章

  • C语言实现十进制转为二进制 递归法
    //ConsoleApplication15.cpp:此文件包含"main"函数。程序执行将在此处开始并结束。//  #include<iostream>#include<stdio.h>usingnamespacestd;voidto_binary(unsignedlongn);intmain(void){  unsignedlongnumber;  printf("Enteraninteger(......
  • Linux下MySql的三种安装方式:RPM 二进制包和源代码
    mysql的三种安装方式:RPM二进制包和源代码本次安装的系统平台为redhat5一、使用RPM包进行安装    首先可以从安装光盘中或者到mysql的网站上下载对应版本的rpm包如下:MySQL-server-community-5.1.38-0.rhel5.i386.rpmMySQL-client-community-5.1.38-0.rhel5.i386.rpm   ......
  • feign传递文件、传递二进制流
    传递文件服务端@RestControllerpublicclassDemoController{@PostMapping("/upload")@ApiOperation("上传文件")publicvoidupload(@RequestParam("file")MultipartFilefile)throwsException{ //todo}}客户端申明接口主要是加上consu......
  • 二进制CRC校验码生成程序
      /**二进制CRC序列生成程序*/#include<stdio.h>#include<string.h>#defineLEN_DIVIDEND30#defineLEN_DIVISOR30#defineLEN_SEQUENCELEN_DIVIDEND+LEN_DIVISORvoidCRC(char*,char*,char*);voidMOD2_div(char*,char*,char*);voidmove(char*,int);intmai......
  • 以二进制文件安装K8S之高可用部署架构
    在Kubernetes系统中,Master节点扮演着总控中心的角色,通过不间断地与各个工作节点(Node)通信来维护整个集群的健康工作状态,集群中各资源对象的状态则被保存在etcd数据库中。在正式环境中应确保Master的高可用,并启用安全访问机制,至少包括以下几方面。Master的kube-apiserver、kube-c......
  • 以二进制文件安装K8S之创建CA根证书
    为etcd和Kubernetes服务启用基于CA认证的安全机制,需要CA证书进行配置。如果组织能够提供统一的CA认证中心,则直接使用组织颁发的CA证书即可。如果没有统一的CA认证中心,则可以通过颁发自签名的CA证书来完成安全配置。如下以通过颁发自签名的CA证书来完成安全配置。etcd和Kubernet......
  • 以二进制文件安装K8S之环境准备
    为了k8s集群能正常运行,需要先完成4项准备工作:1.关闭防火墙2.禁用SeLinux3.关闭Swap4.安装Docker关闭防火墙#查看防火墙状态getenforce#关闭防火墙,禁用防火墙开机自启动systemctlstopfirewalldsystemctldisablefirewalld禁用SeLinux#临时禁用SeLinux,重启失效......
  • 以二进制文件安装K8S之部署etcd高可用集群
    概述前提条件:已经准备好CA根证书(etcd在制作CA证书时需要CA根证书),并且把CA根证书文件ca.key和ca.crt拷贝到3个etcd节点的/etc/kubernetes/pki目录下。3台主机的IP地址分别为192.168.3.135、192.168.3.136、192.168.3.137。要安装的etcd版本:v3.4.13-linux-amd64。安装etcd下载e......
  • 以二进制文件安装K8S之部署Master高可用集群
    如下以二进制文件方式部署安全的KubernetesMaster高可用集群,具体步骤如下:1.下载Kubernetes服务的二进制文件2.部署kube-apiserver服务3.创建客户端CA证书4.创建客户端连接kube-apiserver服务所需的kubeconfig配置文件5.部署kube-controller-manager服务6.部署kube-schedule......
  • 详解二进制,八进制,十进制,十六进制的原理与转换
    首先了解一下数字系统的由来数字系统是人类为了表示数量和进行计数而创造的一种工具。数字系统的发展可以追溯到古代文明,不同的文化和社会在不同的时间和地点创造了各种数字系统。以下是数字系统的一些关键发展阶段: 早期计数:最早的人类社会使用自然物体如石块、棍子、贝壳等......