Codeforces 909C Python Indentation:树状数组优化dp

题目链接:http://codeforces.com/contest/909/problem/C

题意:

  Python是没有大括号来标明语句块的,而是用严格的缩进来体现。

  现在有一种简化版的Python,只有两种语句:

    (1)'s'语句:Simple statements. 相当于一般语句。

    (2)'f'语句:For statements. 相当于for循环,并且规定它的循环体不能为空。

  然后给你一段没有缩进的Python程序,共n行(n <= 5000)。

  问你添加缩进后,有多少种合法且不同的Python程序。

 

题解:

  表示状态:

    dp[i][j] = numbers

    考虑到第i行,并且第i行的缩进有j个Tab时的合法方案数。

 

  找出答案:

    ans = ∑ dp[n-1][0 to n-1]

    行号从0开始标。并且对于第i行来说,它的缩进最多有i个Tab。

 

  如何转移:

    两种情况。

    当前为dp[i][j](用顺推)。

    (1)第i行为'f',则第i+1行的缩进只能为j+1。

      dp[i+1][j+1] += dp[i][j]

    (2)第i行为's',则第i+1行的缩进可以为[0,j]中的任意一种。

      dp[i+1][0 to j] += dp[i][j]

 

  边界条件:

    dp[0][0] = 1

    第0行的缩进只能为0。

 

  树状数组优化:

    如果按照上面的方程直接去写的话,枚举状态为O(N^2),转移的第二种情况复杂度为O(N)。

    所以最坏情况下为O(N^3),对于N = 5000肯定炸了……

    所以考虑用树状数组来实现转移的第二种情况,也就是区间加法和单点查询。

    于是总复杂度变为O(N^2*logN)。

    另外,树状数组下标从1开始,所以之前所有的下标都要+1。

 

  update:

    其实顺推也可以用差分优化掉一个n的啊……

    (打比赛的时候人是瓷的……)

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define MAX_N 5005
 5 #define MOD 1000000007
 6 
 7 using namespace std;
 8 
 9 int n;
10 int dp[MAX_N][MAX_N];
11 char c[MAX_N];
12 
13 void update(int *dat,int k,int x)
14 {
15     while(k>0)
16     {
17         dat[k]=(dat[k]+x)%MOD;
18         k-=k&-k;
19     }
20 }
21 
22 int query(int *dat,int k)
23 {
24     int sum=0;
25     while(k<=n)
26     {
27         sum=(sum+dat[k])%MOD;
28         k+=k&-k;
29     }
30     return (sum%MOD+MOD)%MOD;
31 }
32 
33 void sec(int *dat,int l,int r,int x)
34 {
35     update(dat,r,x);
36     update(dat,l-1,-x);
37 }
38 
39 int main()
40 {
41     cin>>n;
42     for(int i=1;i<=n;i++) cin>>c[i];
43     memset(dp,0,sizeof(dp));
44     sec(dp[1],1,1,1);
45     for(int i=1;i<=n;i++)
46     {
47         for(int j=1;j<=i;j++)
48         {
49             int now=query(dp[i],j);
50             if(now)
51             {
52                 if(c[i]=='f')
53                 {
54                     sec(dp[i+1],j+1,j+1,now);
55                 }
56                 else
57                 {
58                     sec(dp[i+1],1,j,now);
59                 }
60             }
61         }
62     }
63     int ans=0;
64     for(int i=1;i<=n;i++)
65     {
66         ans=(ans+query(dp[n],i))%MOD;
67     }
68     cout<<ans<<endl;
69 }

 

posted @ 2017-12-28 14:29  Leohh  阅读(985)  评论(2编辑  收藏  举报