Codeforces 909C Python Indentation:樹狀陣列優化dp

Leohh發表於2017-12-28

題目連結: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 }

 

相關文章