和零在一起

31 阅读3分钟

小强有一个长度为n的01字符串str,他想将字符串划分为几部分,且每部分都有且只有一个0,小强只会去验证划分方案的正确性,但是小强他不知道对于这个字符串一共有多少总划分的方案,请你告诉小强总的方案数,方案可能很大请对10^9十7取模。

要解决这个问题,核心是先判断字符串是否满足 “每部分有且只有一个 0” 的划分前提,若满足则计算相邻 0 之间 1 的数量组合,若不满足则方案数为 0。

一、核心判断:是否存在有效划分的前提

一个 01 字符串能被有效划分的唯一前提是:字符串中必须包含 0,且所有 0 的数量决定了划分的固定段数。

  1. 若字符串中没有 0:无法满足 “每部分有一个 0” 的要求,方案数直接为 0。
  1. 若字符串中有k 个 0:则必须划分为 k 段(每段 1 个 0),此时只需计算相邻 0 之间 1 的数量组合,即可得到总方案数。

二、方案数计算:相邻 0 之间的 1 决定组合数

当确定有 k 个 0 时,划分的关键在于 “如何在相邻 0 之间的 1 中插入分割线”,具体步骤如下:

  1. 提取相邻 0 的间隔:计算每两个连续 0 之间包含的 1 的数量,得到一个间隔列表。例如字符串 “010110”,0 的位置在 0、2、5,间隔 1 的数量为:第 1-2 个 0 之间有 1 个 1,第 2-3 个 0 之间有 2 个 1,间隔列表为 [1,2]。
  1. 计算每段间隔的可选数:对于两个 0 之间的 m 个 1,分割线只能插在 1 的 “缝隙” 中(包括前后),共有m + 1种选择。例如 m=1(1 个 1)时,有 2 种选择(在 1 前分割或 1 后分割);m=2(2 个 1)时,有 3 种选择。
  1. 总方案数为所有间隔可选数的乘积:将每个间隔的m + 1相乘,结果即为总方案数,最终对10^9 + 7取模。

三、示例验证

以具体例子说明计算过程,直观理解逻辑:

字符串0 的数量 k相邻 0 的间隔(1 的数量)每间隔可选数(m+1)总方案数(乘积)结果(模 1e9+7)
"0"1无间隔(k=1 时无分割)11
"010"2[1]1+1=222
"011010"3[2,1]2+1=3;1+1=23×2=66
"111"000

四、算法步骤(可直接落地代码)

  1. 遍历字符串,统计 0 的个数zero_count,并记录每个 0 的位置。
  1. 若zero_count == 0,返回 0;若zero_count == 1,返回 1。
  1. 计算相邻 0 的位置差,减去 1(得到间隔的 1 的数量 m),生成间隔列表。
  1. 初始化结果res = 1,遍历间隔列表,将每个(m + 1)与res相乘,每次相乘后对10^9 + 7取模。
  1. 返回最终的res。

算法实现

const rl = require("readline").createInterface({ input: process.stdin });
var iter = rl[Symbol.asyncIterator]();
const readline = async () => (await iter.next()).value;

void (async function () {
    // Write your code here
    let params = [];
    while ((line = await readline())) {
        let tokens = line.split(" ");
        params.push(tokens);
    }
    // console.log(params)
    let MOD = 1e9 + 7;
    let n = parseInt(params[0][0]);
    let str = params[1][0];

    function count(str) {
        let zeroPositions = [];
        for (let i = 0; i < str.length; i++) {
            if (str[i] === "0") {
                zeroPositions.push(i);
            }
        }
        let zeroCount = zeroPositions.length;
        if (zeroCount === 0) {
            // console.log(0);
            return 0;
        }
        if (zeroCount === 1) {
            // console.log(1);
            return 1;
        }
        let ans = 1;
        for (let i = 1; i < zeroCount; i++) {
            ans = (ans * (zeroPositions[i] - zeroPositions[i - 1])) % MOD;
        }
        return ans;
    }
    console.log(count(str));
})();