ARC-059F - Unhappy Hacking - 动态规划

题解链接

https://www.lucien.ink/archives/225/


题目链接

https://arc059.contest.atcoder.jp/tasks/arc059_d


题目

Problem Statement

Sig has built his own keyboard. Designed for ultimate simplicity, this keyboard only has 3 3 keys on it: the 0 key, the 1 key and the backspace key.

To begin with, he is using a plain text editor with this keyboard. This editor always displays one string (possibly empty). Just after the editor is launched, this string is empty. When each key on the keyboard is pressed, the following changes occur to the string:

The 0 key: a letter 0 will be inserted to the right of the string.
The 1 key: a letter 1 will be inserted to the right of the string.
The backspace key: if the string is empty, nothing happens. Otherwise, the rightmost letter of the string is deleted.
Sig has launched the editor, and pressed these keys N times in total. As a result, the editor displays a string s s . Find the number of such ways to press the keys, modulo 109+7.

Constraints

  • 1N5000 1 ≤ N ≤ 5000
  • 1|s|N 1 ≤ | s | ≤ N
  • s s consists of the letters 0 and 1.

Partial Score

400 points will be awarded for passing the test set satisfying 1≦N≦300.


题意

  有一个键盘只有三个按键,01Back Space,每按一下就会在屏幕上输出一个01或者是删掉一个数字,屏幕上没字的时候按退格键不会发生任何事。问你按了n下键盘之后屏幕上显示的是字符串s的方案数是多少。


思路

  应该是有O(n)的做法的,但是目前来说我只会 O(n2) O ( n 2 ) 的做法,讲一下 O(n2) O ( n 2 ) 的吧。

  记 f[i][j] f [ i ] [ j ] 为按了i下键盘之后产生了长度为j的串的方案数,初始 f[0][0]=1 f [ 0 ] [ 0 ] = 1

  对于某个f[i][j],要么按一次数字键(0或者1)变成f[i + 1][j + 1],要么按一次退格键变成f[i + 1][j - 1],也就是说,每一个f[i][j]只会对两个状态产生影响,但是一个f[i][j]会被很多状态影响,显然从ii + 1会简单很多,则有:

  • f[i + 1][j + 1] += 2 * f[i][j]
  • f[i + 1][max(j - 1, 0)] += f[i][j]

  注意j = 0的时候相当于屏幕上此时没有字符,此时按退格键虽然不会改变字符,但仍然是一个有效状态,所以取max(j - 1, 0)

  这样仅仅是得到了按i下键盘时得到了长度为j的串的方案数,但是题目里所给的串是一个特定的串,是所有长度为j的串的其中之一,又因为长度为j的串中每个字符要么是0要么是1,总共有 2 j 2   j 种串,所以按n下得到某个长度为len的串的方案数应为 f[n][len]2j f [ n ] [ l e n ] 2 j


实现

#include <bits/stdc++.h>
const int maxn = 5007, mod = int(1e9) + 7;
typedef long long ll;
char str[maxn];
int ans[maxn][maxn], len, n;
ll power_mod(ll p, int q) {
    ll ret = 1;
    while (q) {
        if (q & 1) ret = ret * p % mod;
        p = p * p % mod;
        q >>= 1;
    }
    return ret;
}
int max(int a, int b) { return a > b ? a : b; }
void init() {
    len = int(strlen(str)), ans[0][0] = 1;
    for (int i = 0; i <= n; i++) {
        for (int j = 0; j <= i; j++) {
            ans[i + 1][j + 1] = int((1ll * ans[i][j] * 2 % mod + ans[i + 1][j + 1]) % mod);
            ans[i + 1][max(j - 1, 0)] = int((0ll + ans[i][j] + ans[i + 1][max(j - 1, 0)]) % mod);
        }
    }
}

int main() {
    scanf("%d%s", &n, str);
    init();
    printf("%d\n", int(power_mod(power_mod(2, len), mod - 2) * ans[n][len] % mod));
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 很高兴回答你的问题。请看下面的代码: #include <stdio.h> int main() { long long n; int count = ; scanf("%lld", &n); while (n > ) { if (n % 10 == 6) { count++; printf("6"); } n /= 10; } if (count == ) { printf("Unhappy"); } return ; } 希望能帮到你! ### 回答2: 可以先将正整数n转换成字符串,然后遍历字符串中的每个字符,判断是否为'6',如果是则计数,最后输出计数结果。如果计数结果大于等于1,则输出对应数量的'6',否则输出"Unhappy"。 以下是用Python编写的程序示例: ```python def count_six(n): num_str = str(n) # 将正整数n转换为字符串 count = 0 # 初始化计数器 # 遍历字符串中的每个字符 for ch in num_str: if ch == '6': count += 1 # 如果字符为'6',计数器加1 if count >= 1: return '6' * count # 输出对应数量的'6' else: return 'Unhappy' # 示例输入 n = 1689466 result = count_six(n) print(result) # 输出: 666 n = 421078951 result = count_six(n) print(result) # 输出: Unhappy ``` 以上程序中定义了一个`count_six`函数,接受一个正整数n作为参数,并根据题目要求进行计数和输出操作。示例输入中的两个例子分别演示了有6和没有6的情况。 ### 回答3: 可以通过将数字n转换为字符串,然后遍历字符串中的每个字符,判断是否为字符'6'来统计数字中出现的6的个数。 下面是一个示例的Python代码实现: ```python def count_six(n): str_n = str(n) count = 0 for digit in str_n: if digit == '6': count += 1 return count n = int(input("请输入一个正整数n:")) result = count_six(n) if result > 0: print('6' * result) else: print('Unhappy') ``` 该代码首先将输入的数字n转换为字符串,然后使用一个计数器count来记录数字中出现的6的个数。接下来,通过遍历字符串中的每个字符,判断是否为字符'6',如果是,则将计数器count加1。 最后,判断计数器count的值,如果大于0,则输出相应个数的字符'6';如果等于0,则输出'Unhappy'表示没有出现6。 注意,这个程序是通过将输入的数字转换为字符串来实现的,该方法可用于处理n的范围在10^18内的情况。如果n的范围更大,可能需要使用其他方法进行处理。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值