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] \times 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();
}
}