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


    C. Python Indentation
    time limit per test2 seconds
    memory limit per test256 megabytes
    inputstandard input
    outputstandard output
    In Python, code blocks don't have explicit begin/end or curly braces to mark beginning and end of the block. Instead, code blocks are defined by indentation.

    We will consider an extremely simplified subset of Python with only two types of statements.

    Simple statements are written in a single line, one per line. An example of a simple statement is assignment.

    For statements are compound statements: they contain one or several other statements. For statement consists of a header written in a separate line which starts with "for" prefix, and loop body. Loop body is a block of statements indented one level further than the header of the loop. Loop body can contain both types of statements. Loop body can't be empty.

    You are given a sequence of statements without indentation. Find the number of ways in which the statements can be indented to form a valid Python program.

    Input
    The first line contains a single integer N (1 ≤ N ≤ 5000) — the number of commands in the program. N lines of the program follow, each line describing a single command. Each command is either "f" (denoting "for statement") or "s" ("simple statement"). It is guaranteed that the last line is a simple statement.

    Output
    Output one line containing an integer - the number of ways the given sequence of statements can be indented modulo 109 + 7.

    Examples
    inputCopy
    4
    s
    f
    f
    s
    outputCopy
    1
    inputCopy
    4
    f
    s
    f
    s
    outputCopy
    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

    题意:
    Python是没有大括号来表明语句块的,而是用严格的缩进来体现
    现在有简化版的Python,只有两种语句,
    (1)'s'语句:Simple statements. 相当于一般语句。

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

    现在给你一个没有缩进的Python程序,共n行,问你添加缩进后,有多少种合法且不同的Python程序。

    思路: dp,定义状态:dp[i][j] 考虑到第i行,并且第i行的缩进有j个tab时的合法方案数。

    答案就是 sum { dp[n-1][0 ~ n-1] }

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

    状态转移:

    当前第i行为‘f' ,则第i+1行的缩进只能为j+1
    dp[i+1][j+1]+=dp[i][j];
    或者第i行为's' ,则第i+1行的缩进可以为[0,j] 中任意一种、
    dp[i+1][0 to j] +=dp[i][j];

    初始条件:
    dp[0][0]=1

    树状数组优化:

    按照上面的转移方程去写,枚举状态是nn,第二种转移的时间复杂度是n,所以时间复杂度是nn*n,肯定会tle的,

    所以我们考虑用树状数组来实现转移第2种情况,利用差分数组,进行区间修改,区间/单点查询。

    时间复杂度就是 nnlogn
    另外bit从下标1开始,所以之前所有下标都要加1

    Ps:还有一个值得注意的是,区间修改时,add(data,r+1,-x); ,给加了负值,会出现负数,所以取模的时候一定要是( dp[id] +mod )%mod ,不注意很容易wa

    细节见代码:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <map>
    #include <set>
    #include <vector>
    #include <iomanip>
    #define ALL(x) (x).begin(), (x).end()
    #define rt return
    #define dll(x) scanf("%I64d",&x)
    #define xll(x) printf("%I64d
    ",x)
    #define sz(a) int(a.size())
    #define all(a) a.begin(), a.end()
    #define rep(i,x,n) for(int i=x;i<n;i++)
    #define repd(i,x,n) for(int i=x;i<=n;i++)
    #define pii pair<int,int>
    #define pll pair<long long ,long long>
    #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
    #define MS0(X) memset((X), 0, sizeof((X)))
    #define MSC0(X) memset((X), '', sizeof((X)))
    #define pb push_back
    #define mp make_pair
    #define fi first
    #define se second
    #define eps 1e-6
    #define gg(x) getInt(&x)
    #define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
    using namespace std;
    typedef long long ll;
    ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
    ll lcm(ll a,ll b){return a/gcd(a,b)*b;}
    ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;}
    inline void getInt(int* p);
    const int maxn=1000010;
    const int inf=0x3f3f3f3f;
    /*** TEMPLATE CODE * * STARTS HERE ***/
    int n;
    const ll mod=1e9+7ll;
    ll dp[5005][5005];
    char s[maxn];
    int lowbit(int x)
    {
         return x&(-x);
    }
    void add(ll *data,int id,ll x)
    {
        while(id<=n)
        {
            data[id]+=x;
            data[id]=(data[id]+mod)%mod;
            id+=lowbit(id);
        }
    }
    ll query(ll *data,int x)
    {
        ll res=0ll;
        while(x)
        {
            res=(res+data[x])%mod;
            x-=lowbit(x);
        }
        return res;
    }
     
    void update(ll *data,int l,int r,ll x)
    {
        add(data,l,x);
        add(data,r+1,-x);
    }
     
    int main()
    {
        //freopen("D:\common_text\code_stream\in.txt","r",stdin);
        //freopen("D:\common_textcode_stream\out.txt","w",stdout);
        gbtb;
        cin>>n;
        repd(i,1,n)
        {
            cin>>s[i];
        }
        MS0(dp);
        update(dp[1],1,1,1);
        repd(i,1,n-1)
        {
            repd(j,1,i)
            {
                ll now=query(dp[i],j);
                if(now)
                {
                    if(s[i]=='f')
                    {
                        update(dp[i+1],j+1,j+1,now);
                    }else
                    {
                        update(dp[i+1],1,j,now);
                    }
                }
            }
        }
        ll ans=0ll;
        repd(i,1,n)
        {
            // chu(query(dp[n],i));
            ans=(ans+query(dp[n],i))%mod;
        }
        cout<<ans<<endl;
        
        
        return 0;
    }
     
    inline void getInt(int* p) {
        char ch;
        do {
            ch = getchar();
        } while (ch == ' ' || ch == '
    ');
        if (ch == '-') {
            *p = -(getchar() - '0');
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 - ch + '0';
            }
        }
        else {
            *p = ch - '0';
            while ((ch = getchar()) >= '0' && ch <= '9') {
                *p = *p * 10 + ch - '0';
            }
        }
    }
     
    
    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    Springboot vue 前后分离 跨域 Activiti6 工作流 集成代码生成器 shiro权限
    mybatis3批量更新 批量插入
    Java GC的工作原理详解
    Hadoop的Map侧join
    cut 命令
    head 与 tail
    常用正则
    vim 设置
    Java泛型初探
    linux修改PS1,自定义命令提示符样式
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/11164079.html
Copyright © 2020-2023  润新知