Atcoder Regular Contest 59_F

F - Unhappy Hacking

问题描述

Sig 制作了自己的键盘。设计的极简风格,这个键盘上只有 3 个按键:按键 0、按键 1 和退格键。

一开始,他在使用一个普通文本编辑器与这个键盘配合。这个编辑器总是显示一个字符串(可能为空)。在编辑器启动后,这个字符串是空的。当按下键盘上的每个按键时,字符串会发生以下变化:

  • 按键 0:会在字符串右侧插入一个字母 0
  • 按键 1:会在字符串右侧插入一个字母 1
  • 退格键:如果字符串为空,则不会发生任何变化。否则,会删除字符串最右侧的一个字母。

Sig 启动了编辑器,并总共按下这些按键 𝑁 次。结果,编辑器显示的字符串为 𝑠。找出按下按键的方式数量,对 1e9+7 取模后的结果。

约束条件

1\leqslant n\leqslant 5000

1\leqslant \mid s\mid\leqslant n

s 由字母 0 和 1 组成。

输入

输入以以下格式从标准输入给出:

N
s

输出

输出按下按键 𝑁 次总共的方式数量,使得编辑器最终显示字符串 𝑠,对 1e9+7 取模后的结果。

示例 1

Input
3
0
Output
5

我们用 B 表示退格键。以下 5 种按键方式会导致编辑器最终显示字符串 0: 00B01B0B01B0BB0。在最后一种方式中,按下退格键时不会发生任何变化。

示例 2

Input
300
1100100
Output
519054663

示例 3

Input
5000
01000001011101000100001101101111011001000110010101110010000
Output
500886057

题解

    对于此题1\leqslant n\leqslant 5000考虑二维动态规划。

    定义

           定义dp[i][j]表示第i次操作后,剩下j个字符的方案数。

    转移

           考虑刷表,当前第i+1次操作有两种可能:

           1.按键0/按键1:加了一个字符,更新dp[i][j],因为两种情况,所以要乘2

           2.退格键:此时我们删除的是第j位的字符,因为可能没有字符,所以要与0取最大值。因为我                                 们是删除一个字符,所以可以不用讨论是1还是0的情况,因此不用乘2。

   答案

           原本是dp[n][s.size()],但是我们注意到一个问题:我们只是考虑了剩下n.size()位,并没有考虑               每一位上是0/1,所以我们需要除以pow(2,n.size()),但因为这里要取模,所以要用快速幂。

 代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAXN = 5005;
const int mod = 1e9 + 7;
char s[MAXN];
ll dp[MAXN][MAXN];
ll p(ll x, ll y)
{
    ll sum = 1;
    while (y != 0)
    {
        if (y & 1)
            sum = sum * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return sum % mod;
}
int main()
{
    int n;
    scanf("%d%s", &n, s + 1);
    int m = strlen(s + 1);
    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 + 1][j + 1] + 2 * dp[i][j]) % mod;
            dp[i + 1][max(j - 1, 0)] = (dp[i + 1][max(j - 1, 0)] + dp[i][j]) % mod;
        }
    printf("%lld", dp[n][m] * (p(p(2, m), mod - 2) % mod) % mod);
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值