[ARC059F] Unhappy Hacking

题意

一个打字机,有 \(1, 0\)\(B\)

其中 \(B\) 代表退格。

求操作长度为 \(n\),能打出字符串 \(s\) 的方案数。

\(n \le 5 \times 10 ^ 3\)

Sol

发现一个很厉害的事情,最终的方案数与 \(s\) 的形态无关,也就是说我们根本不在意每个位置选啥,只需要在最后除以 \(2 ^ m\) 就可以了。

\(f_{i, j}\) 表示操作了 \(i\) 次,字符串长度为 \(j\) 的方案数(不要求合法)。

\[f_{i, j} = \begin{cases} 2 \times f_{i - 1, j - 1} \\ f_{i - 1, j + 1} \end{cases} \]

最后乘上 \(2 ^ {-m}\) 即可。

复杂度:\(O(n ^ 2)\)

Code

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
using namespace std;
int read() {
    int p = 0, flg = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') flg = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        p = p * 10 + c - '0';
        c = getchar();
    }
    return p * flg;
}
void write(int x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x > 9) {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}
bool _stmer;

const int N = 5005, mod = 1e9 + 7;

int pow_(int x, int k) {
    int ans = 1;
    while (k) {
        if (k & 1) ans = 1ll * ans * x % mod;
        x = 1ll * x * x % mod;
        k >>= 1;
    }
    return ans;
}

array <array <int, N>, N> f;

void Mod(int &x) {
    if (x >= mod) x -= mod;
    if (x < 0) x += mod;
}

char strbuf[N];

bool _edmer;
int main() {
    cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
    int n = read();
    scanf("%s", strbuf);
    string s = strbuf;
    int m = s.size();
    f[0][0] = 1;
    for (int i = 1; i <= n; i++) {
        f[i][0] = f[i - 1][0];
        for (int j = 0; j <= i; j++)
            f[i][j] += ((j ? 2ll * f[i - 1][j - 1] % mod : 0) + f[i - 1][j + 1]) % mod, Mod(f[i][j]);
    }
    write(1ll * f[n][m] * pow_(pow_(2, m), mod - 2) % mod), puts("");
    return 0;
}
posted @ 2024-04-01 17:04  cxqghzj  阅读(27)  评论(0)    收藏  举报