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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
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;
}

你可能感兴趣的:(ACM - 动态规划)