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

[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\)​ ,则 \[ \begin{aligned} &f(i + 1,\,a,\,1) \uparrow f(i,\,a,\,2) + f(i,\,a,\,0) \\[6pt] &f(i + 1,\,a,\,2) \uparrow f(i,\,a,\,1) \end{aligned} \]

  • \(s_{i+1} = \mathtt 1\)​ ,则 \[ \begin{aligned} &f(i + 1,\,a,\,b-1) \uparrow f(i,\,a,\,b) &(b\ne 0) \\[8pt] & \begin{cases} f(i + 1,\,1,\,0)\uparrow f(i,\,0,\,0) \\[6pt] f(i + 1,\,2,\,0)\uparrow f(i,\,1,\,0) \\[6pt] f(i + 1,\,2,\,0)\uparrow f(i,\,2,\,0) \end{cases} & (b = 0) \end{aligned} \]

  • \(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 !
评论
  目录