嘘~ 正在从服务器偷取页面 . . .

[AGC022E] Median Replace 题解


[AGC022E] Median Replace 题解

题目链接:[AGC022E] Median Replace

题意

有个长度为 $N$($N$ 为奇数)的 $\texttt{01}$ 串 $s$,其中有若干位置是 $\texttt{?}$。

一次操作可将 $3$​ 个连续的字符替换成这三个数的中位数。

求有多少将 $\texttt ?$ 替换成 $\texttt0$ 或 $\texttt1$ 的方案使得进行 $\frac{N-1}{2}$ 次操作后的字符串可以是 $\texttt1$​。

输入格式

一行,给定 $s$ 。

输出格式

一行,答案

数据范围

$1\leq N\leq300000$ 且 $N$ 为奇数。

做多替换三个的题了,还以为是把每个位置都换成中位数……(我就说大早上写题会弱智吧

容易发现,如果一个字符串由 $a$ 个连续的 $\mathtt{1}$ 和 $b$ 个连续的 $\mathtt{0}$ 拼接而成,则当 $a > b$ 时一定合法。

考虑维护一个从栈顶到栈底由一段连续的 $\mathtt{0}$ 和一段连续的 $\mathtt{1}$ 组成的栈,然后依次加入每个 $s_i$ ,则

  • 若 $s_i = \mathtt{0}$​​ ,
    • 若栈顶为 $\mathtt 0$ ,当栈顶有 $2$ 个 $\mathtt 0$ 时可以替换成一个 $\mathtt 0$ ,否则入栈。
    • 若栈顶为 $\mathtt 1$ ,直接入栈。
  • 若 $s_i = \mathtt{1}$ ,
    • 若栈顶为 $\mathtt 0$ ,新加入的 $\mathtt 1$ 可以和栈顶的 $\mathtt 0$ 抵消。
    • 若栈顶为 $\mathtt 1$ ,仅在 $\mathtt 1$ 只有一个时加入。

那么这个栈就用很小的状态数就维护了一个串是否合法。

于是可以考虑 dp 了。设 $f(i,a,b)$ 为考虑到第 $i$ 位,栈内有 $a$ 个 $\mathtt 1$ 和 $b$ 个 $\mathtt 0$ 的方案数,考虑转移:

  • 若 $s_{i+1}=\mathtt 0$​ ,则

  • 若 $s_{i+1} = \mathtt 1$​ ,则

  • 若 $s_{i + 1} = \mathtt{?}$ ,则把上面两种转移都做一遍即可。

时间复杂度 $\mathcal{O}(n)$

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
const int mod = 1e9 + 7;
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
void add(int &x, int y) { (x += y) >= mod ? x -= mod : 0; }
#define N ((int)(3e5 + 15))

char s[N];
int n, f[N][3][3];
signed main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);
    // freopen("check.in","r",stdin);
    // freopen("check.out","w",stdout);
    cin >> (s + 1); n = strlen(s + 1); f[0][0][0] = 1;
    for(int i = 0; i < n; i++)
    {
        if(s[i + 1] != '1') {
            for(int a = 0; a <= 2; a++)
            {
                add(f[i + 1][a][1], f[i][a][2]);
                add(f[i + 1][a][2], f[i][a][1]);
                add(f[i + 1][a][1], f[i][a][0]);
            }
        }
        if(s[i + 1] != '0') {
            for(int a = 0; a <= 2; a++)
            {
                add(f[i + 1][a][0], f[i][a][1]);
                add(f[i + 1][a][1], f[i][a][2]);
            }
            add(f[i + 1][1][0], f[i][0][0]);
            add(f[i + 1][2][0], f[i][1][0]);
            add(f[i + 1][2][0], f[i][2][0]);
        }
    }
    int res = 0;
    for(int a = 0; a <= 2; a++)
        for(int b = 0; b <= a; b++) add(res, f[n][a][b]);
    cout << res << '\n';
    return 0;
}

参考文献

[1] https://www.luogu.com.cn/article/t1y87bs5


题外话

题又不会做…睡觉睡觉(困)


文章作者: q779
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-ND 4.0 许可协议。转载请注明来源 q779 !
评论
  目录