当前位置: 首页 > news >正文

dp+容斥原理,LeetCode 3130. 找出所有稳定的二进制数组 II

一、题目

1、题目描述

给你 3 个正整数 zero ,one 和 limit 。

一个 

二进制数组

  arr 如果满足以下条件,那么我们称它是  稳定的 :
  • 0 在 arr 中出现次数 恰好 为 zero 。
  • 1 在 arr 中出现次数 恰好 为 one 。
  • arr 中每个长度超过 limit 的 

    子数组

     都 同时 包含 0 和 1 。

请你返回 稳定 二进制数组的  数目。

由于答案可能很大,将它对 109 + 7 取余 后返回。

2、接口描述

python3
 ​
class Solution:def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:
 ​
c++
class Solution {
public:int numberOfStableArrays(int zero, int one, int limit) {}
};

C# 
 
public class Solution {public int NumberOfStableArrays(int zero, int one, int limit) {}
}

3、原题链接

3130. 找出所有稳定的二进制数组 II


二、解题报告

1、思路分析

定义状态f(i, j, k) 为 用 i 个0,j 个 1,并且最后一个为k的合法方案数(即没有连续limit 以上相同的0或者1)

那么如何状态转移?

当前是0/1,前一个自然也可以是0/1

以f(i, j, 0)为例,我们当前的0可以加在f(i - 1, j, 0) 和 f(i, j - 1, 0) 后面,显然会出现非法情况,即接上一个0,出现大于连续limit个0,所以要减去加上这个0后,最大连续0为limit + 1的情况

因为定义的状态为合法方案,所以合法方案加上1个0出现的非法方案只可能是limit + 1个连续0的情况,并且这limit + 1 个0是后缀

即我们要减去 f(i - limit - 1, j, 1),因为后缀是limit + 1个0,后缀0前面一定是1

于是有了状态转移方程:

f[i][j][0] = (f[i - 1][j][0] + f[i - 1][j][1] - (f[i - limit - 1][j][1] if i > limit else 0)
f[i][j][1] = f[i][j - 1][0] + f[i][j - 1][1] - (f[i][j - limit - 1][0] if j > limit else 0)

总结:其实就是将方案划分为不重不漏的状态集合,利用容斥原理完成状态转移

2、复杂度

时间复杂度: O(zero * one)空间复杂度:O(zero * one)

3、代码详解

python3
 
P = 1_000_000_007
class Solution:def numberOfStableArrays(self, zero: int, one: int, limit: int) -> int:f = [[[0] * 2 for j in range(one + 1)] for i in range(zero + 1)]for j in range(1, min(one + 1, limit + 1)):f[0][j][1] = 1for i in range(1, min(zero + 1, limit + 1)):f[i][0][0] = 1for i in range(1, zero + 1):for j in range(1, one + 1):f[i][j][0] = (f[i - 1][j][0] + f[i - 1][j][1] - (f[i - limit - 1][j][1] if i > limit else 0)) % Pf[i][j][1] = (f[i][j - 1][0] + f[i][j - 1][1] - (f[i][j - limit - 1][0] if j > limit else 0)) % Preturn (f[zero][one][0] + f[zero][one][1]) % P 
c++
constexpr int P = 1'000'000'007;
class Solution {
public:int numberOfStableArrays(int zero, int one, int limit) {std::vector<std::vector<std::array<int, 2>>> f(zero + 1, std::vector<std::array<int, 2>>(one + 1));for (int i = 1; i <= std::min(zero, limit); ++ i)f[i][0][0] = 1;for (int i = 1; i <= std::min(one, limit); ++ i)f[0][i][1] = 1;for (int i = 1; i <= zero; ++ i)for (int j = 1; j <= one; ++ j) {f[i][j][0] = (1LL * f[i - 1][j][0] + f[i - 1][j][1] - (i > limit ? f[i - limit - 1][j][1] : 0)) % P;f[i][j][0] = (1LL * f[i][j][0] + P) % P;f[i][j][1] = (1LL * f[i][j - 1][0] + f[i][j - 1][1] - (j > limit ? f[i][j - limit - 1][0] : 0)) % P;f[i][j][1] = (1LL * f[i][j][1] + P) % P;}return (1LL * f[zero][one][0] + f[zero][one][1]) % P;}
};
 C#
public class Solution {const int P = 1000000007;public int NumberOfStableArrays(int zero, int one, int limit) {int[,,] f = new int[zero + 1, one + 1, 2];for (int i = 1; i <= Math.Min(zero, limit); ++ i)f[i, 0, 0] = 1;for (int i = 1; i <= Math.Min(one, limit); ++ i)f[0, i, 1] = 1;for (int i = 1; i <= zero; ++ i)for (int j = 1; j <= one; ++ j) {f[i, j, 0] = (int)(((long)f[i - 1, j, 0] + f[i - 1, j, 1] - (i > limit ? f[i - limit - 1, j, 1] : 0)) % P);f[i, j, 0] = (int)(((long)f[i, j, 0] + P) % P);f[i, j, 1] = (int)(((long)f[i, j - 1, 0] + f[i, j - 1, 1] - (j > limit ? f[i, j - limit - 1, 0] : 0)) % P);f[i, j, 1] = (int)(((long)f[i, j, 1] + P) % P);}return (int)(((long)f[zero, one, 0] + f[zero, one, 1]) % P);}
}
 

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【学习总结】MySQL篇
  • 我的API定义规范(未完待续,欢迎指正)
  • 关于缓存的一些心得
  • unity对象缓存技术ObjectPool
  • 【算法】KMP算法
  • 硬盘分区读不出来:原因深度剖析与高效恢复实践
  • 通用分页处理:从繁琐到简洁的转变
  • PYTHON专题-(7)python都有包了?
  • 【王道数据结构-第二章-线性表算法题】
  • 50etf期权行权采用什么交割方式 ?
  • Python爬虫与MySQL完美结合:从环境搭建到实战优化
  • Linux——文件(1)
  • SQL注入实例(sqli-labs/less-9)
  • Ubuntu22.04安装Docker教程
  • 微信开放平台更换服务器证书通知
  • Java教程_软件开发基础
  • MYSQL如何对数据进行自动化升级--以如果某数据表存在并且某字段不存在时则执行更新操作为例...
  • vue学习系列(二)vue-cli
  • 多线程 start 和 run 方法到底有什么区别?
  • 基于游标的分页接口实现
  • 记录:CentOS7.2配置LNMP环境记录
  • 聊聊hikari连接池的leakDetectionThreshold
  • 聊聊redis的数据结构的应用
  • 前端学习笔记之原型——一张图说明`prototype`和`__proto__`的区别
  • 微服务入门【系列视频课程】
  • # 移动硬盘误操作制作为启动盘数据恢复问题
  • $refs 、$nextTic、动态组件、name的使用
  • (10)Linux冯诺依曼结构操作系统的再次理解
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (八十八)VFL语言初步 - 实现布局
  • (附源码)springboot美食分享系统 毕业设计 612231
  • (附源码)计算机毕业设计SSM基于java的云顶博客系统
  • (计算机网络)物理层
  • (九十四)函数和二维数组
  • (论文阅读22/100)Learning a Deep Compact Image Representation for Visual Tracking
  • (论文阅读30/100)Convolutional Pose Machines
  • (十三)Flask之特殊装饰器详解
  • (实战篇)如何缓存数据
  • (四)事件系统
  • (原創) 如何解决make kernel时『clock skew detected』的warning? (OS) (Linux)
  • (原創) 如何優化ThinkPad X61開機速度? (NB) (ThinkPad) (X61) (OS) (Windows)
  • (正则)提取页面里的img标签
  • .ai域名是什么后缀?
  • .dat文件写入byte类型数组_用Python从Abaqus导出txt、dat数据
  • .md即markdown文件的基本常用编写语法
  • .NET MVC 验证码
  • .NET 反射 Reflect
  • .NET关于 跳过SSL中遇到的问题
  • .NET平台开源项目速览(15)文档数据库RavenDB-介绍与初体验
  • .Net中ListT 泛型转成DataTable、DataSet
  • /etc/sudoer文件配置简析
  • [240812] X-CMD 发布 v0.4.5:更新 gtb、cd、chat、hashdir 模块功能
  • [bzoj1912]异象石(set)
  • [BZOJ4010]菜肴制作