AT2022 [ARC059D] バイナリハック / Unhappy Hacking

AT2022 [ARC059D] バイナリハック / Unhappy Hacking

题意:给长度(n <= 5000)和一个长度(len <= 5000)(01)串,要求用键盘(0,1)和回退键来输入,正好花费(n)次恰好输入成(s)串,求方案数。
题解:方案数量大概率是(dp),设(dp)数组(dp_{i,j})表示的是操作(i)次字串长度为(j)的方案数,(无论是啥串,至于为啥先往下看),那么就有两种情况,一种是打(01),还有一种是回退键。

  • 若是输入(01),那么必然(dp[i][j])就是(dp[i-1][j-1])转化来的,那么可以输入(01)两种选择,所以应当是(dp[i + 1][j + 1] = dp[i][j] imes 2).
  • 若是回退键,那么必然(dp[i][j])就是(dp[i-1][j+1])转化来的.
    代码:
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <queue>
#include <vector>
#include <set>

using namespace std;
typedef long long ll;
const int N = 5009;
map<ll, ll>ma;
vector<ll>vec;
const ll mod = 1e9 + 7;
ll dp[N][N];
ll q_pow(ll a, ll k) {
    ll ret = 1;
    ll x = a;
    while (k) {
        if (k & 1) {
            (ret *= x) %= mod;
        }
        k >>= 1;
        (x *= x) %= mod;
    }
    return ret;
}
ll inv(ll a, ll mod) {
    return (q_pow(a, mod-2)%mod + mod) % mod;
}
void solve() {
    int n;cin >> n;
    string s;cin >> s;
    int len = s.size();
    dp[0][0] = 1;
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= i; j++) {
            (dp[i + 1][j + 1] += dp[i][j] * 2 % mod)%=mod;
            (dp[i + 1][max(0, j-1)] += dp[i][j]) %= mod;
        }
    }
    //cout << dp[n][len] << endl;
    //cout << q_pow(2, 1) << endl;
    cout << dp[n][len]  * inv(q_pow(2, len), mod)%mod << endl;
}
signed main() {
    ll t = 1;
    //cin >> t;
    while (t--) {
        solve();
    }
}
原文地址:https://www.cnblogs.com/Xiao-yan/p/14488179.html