文章

2025暑期牛客多校 A.新太阳睡觉中心

2025暑期牛客多校 A.新太阳睡觉中心

Link:Nowcoder

Problem A. 新太阳睡觉中心

题目描述

‘Cause morning rolls around, and it’s another day of sun!

但是作为一个睡瘾患者,肖恩经常睡觉睡个半天,因此,当他醒来时,他甚至记不清今天是星期几。

所以从某一天开始,他开始进行记录:每次他醒来的时候,他就会写下一个数字,表示此时外面是否有阳光。如果有,他会写一个 1;否则,他会写一个 0。在完成记录后,还没等太阳下山,或是太阳升起,他又再次入睡。假设每次肖恩醒来时,他看到的要么是阳光,要么是月光,但不会同时看到两者。

这些记录下来的数字实际上形成了一个长度为 $n$ 的数组:$[a_1, a_2, \dots, a_n]\quad \forall\,1 \le i \le n,\;0 \le a_i \le 1$,其中 $a_i$ 表示肖恩写下的第 $i$ 个数字。

然而,随着时间的推移,一些写下的数字变得模糊不清,你无法判断它是 1 还是 0。如果有 $k$ 个数字无法识别,则可能有 $2^k$ 种不同的数组。

对于每种可能的数组,你都可以依据这个数组计算肖恩看到阳光的最小天数。如果将所有可能数组的最小天数结果相加,得到的总和是多少呢?由于答案可能很大,请将结果对 $998244353$ 取模后输出。

输入格式

  • 第一行包含整数 $T$ $(1 \le T \le 10^4)$,表示测试用例的数量。
  • 每个测试用例包含两行:

    1. 一行整数 $n$ $(2 \le n \le 5\times10^5)$,表示记录的长度。
    2. 一行包含 $n$ 个整数 $a_1, a_2, \dots, a_n$ $( -1 \le a_i \le 1)$,表示每次记录的数字。只有当 $a_i = -1$ 时,该记录未知。

你可以保证所有测试用例中,$\sum n \le 5\times10^5$。

输出格式

对每个测试用例,输出一个整数——所有可能数组的“最小天数”之和,对 $998244353$ 取模后的结果。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
输入:
3
3
1 0 1
3
0 0 0
3
1 -1 1

输出:
2
0
3

解释

  • 示例 1:数组 [1,0,1] 在任意划分中,两个 1 必定来自不同的天,最小天数 = 2。
  • 示例 2:全 0 ,无阳光天数 = 0。
  • 示例 3:未知位可为 0/1,共两种数组:
    • [1,1,1] → 最小天数 = 1
    • [1,0,1] → 最小天数 = 2 总和 = $1 + 2 = 3$。

解析

初看这道题,可能会往DP上面靠,毕竟要转移状态,但是我们分析是很难得到一个明确的转移方程,需要考虑的太多。 其实这道题目的类型是组合计数,如果在数组最前面添上一个0,那么实际计数的就是 $[0,1]$ 作为子数组出现的次数。 我们可以这样来看:

当我们单独看一个 $[i,i+1]$ 子数组的时候,其他位置到底是怎么样,是并不会影响这是一个太阳日的。 因此,此时其他位置的变化实际上只会是 $[i, j]$ 满足 $[0, 1]$ 的一种情况。

当我们只考虑 $i$ 和 $i+1$位置的贡献的时候,一共会有四种情况可能会满足 $[0,1]$:$[0, 1]$, $[-1, 1]$, $[0, -1]$, $[-1, -1]$,其余情况皆不可能。

分别对答案的贡献是 $2^x$, $2^{x - 1}$, $2^{x - 1}$, $2^{x - 2}$。

至此,此题得解。

核心代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int p2[N];

void pre2()
{
    p2[0] = 1;
    for (int i = 1; i < N; i++) p2[i] = (p2[i - 1] * 2) % M;
}

void solve()
{
    int n; cin >> n;
    vector<int> a(n);
    int no = 0;
    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        if (a[i] == -1) no++;
    }
    int ans = 0;
    int u = 0, v = a[0];
    if (v == 1) ans = (ans + p2[no]) % M;
    else if (v == -1) ans = (ans + p2[no - 1]) % M;

    for (int i = 0; i < n - 1; i++)
    {
        u = a[i];
        v = a[i + 1];
        if (u == 0 && v == 1) ans = (ans + p2[no]) % M;
        else if ((u == 0 && v == -1) || (u == -1 && v == 1)) ans = (ans + p2[no - 1]) % M;
        else if (u == -1 && v == -1) ans = (ans + p2[no - 2]) % M;
    }
    cout << ans << endl;
}
本文由作者按照 CC BY 4.0 进行授权