Codeforces - 455 - div. 2 - C - Python Indentation - DP

题目链接:

http://codeforces.com/contest/909/problem/C

题意:

python 语言有两种语句,simple 语句( s 语句)和 for 语句( f 语句)。其中 for 语句的循环体需要缩进一格,并且不能为空( for 语句的循环体里至少有一个 s 语句或 for 语句)。给出 n 条语句,问总共有多少种合法的缩进方法。

输入:

4
s
f
f
s


4
f
s
f
s

输出:

1

2



Note:
In the first test case, there is only one way to indent the program: the second for statement must be part of the body of the first one.


simple statement
for statement
    for statement
        simple statement

In the second test case, there are two ways to indent the program: the second for statement can either be part of the first one's body or a separate statement following the first one.


for statement
    simple statement
    for statement
        simple statement
or


for statement
    simple statement
for statement
    simple statement

数据范围:

  • 1 <= n <= 5000

解题思路:

  • 状态: dp[i][j] 代表第 i 个字符缩进 j 的方案数.
  • 最后答案: ∑dp[n][k] (0<=k<=n-1)
  • 初始化: dp[1][0] = 1
  • 转移方程:
    • 当第 i 个字符是 f 时, 那么第 i + 1 个字符无论是什么,都要缩进一格,所以 dp[i + 1][j + 1] = dp[i][j]
    • 当第 i 个字符是 s 时, 那么第 i + 1 的缩进格数只要 小于等于 第 i 个字符的缩进格数就行.所以dp[i+1][j]=∑dp[i][k] (j<=k<=n-1)
    • 求前缀和的话,枚举缩进格数时可以倒着写.
  • 复杂度: O(n^2)

以下是心路历程:

这题一开始就想到了 dp[i][j]: 第 i 个字符放在第 j 层时的方案数. 最后答案就求个 sum = sum + dp[n][j] 的和.

但…然后写着写着发现思维出现了混乱,觉得这种方法不行.就转去写一维 DP 了.结果是交了三发都 WA 了.直接崩了.最后只能灰溜溜的去看题解了……其实最主要的问题是一开始没有完全想好就开始写了,导致思维混乱.

AC代码:

/********************************************
 *Author*        : dwh
 *Created Time*  : 2018年07月31日 星期二 08时33分55秒

 *********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;
#define lookln(x) cout << #x << " = " << x << endl
#define rep(i,a,n) for(int i = a;i <= n;i++) 
#define per(i,n,a) for(int i = n;i >= a;i--)
const int INF_INT=0x3f3f3f3f;
const long long INF_LL=0x7fffffff;

inline void OPEN(string s){
    freopen((s + ".in").c_str(), "r", stdin);
    freopen((s + ".out").c_str(), "w", stdout);
}

const LL mod = 1e9 + 7;
LL dp[5005][5005],sum;
char s;
int n;

int main(){
    scanf("%d",&n);
    dp[1][0] = 1LL;
    rep(i,1,n){
        scanf(" %c",&s);
        if(s == 'f'){
            rep(j,0,n - 1) dp[i + 1][j + 1] = dp[i][j];
        }
        else{
            sum = 0LL;
            per(j,n - 1,0){
                sum = (sum + dp[i][j]) % mod;
                dp[i + 1][j] = sum;
            }
        }
    }
    sum = 0LL;
    rep(j,0,n - 1){
        sum = (sum + dp[n][j]) % mod;
    }
    printf("%lld\n",sum);
    return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值