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