python 树状数组_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

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define ALL(x) (x).begin(), (x).end()

#define rt return

#define dll(x) scanf("%I64d",&x)

#define xll(x) printf("%I64d\n",x)

#define sz(a) int(a.size())

#define all(a) a.begin(), a.end()

#define rep(i,x,n) for(int i=x;i

#define repd(i,x,n) for(int i=x;i<=n;i++)

#define pii pair

#define pll pair

#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), '\0', 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<

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_text\code_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<

return 0;

}

inline void getInt(int* p) {

char ch;

do {

ch = getchar();

} while (ch == ' ' || ch == '\n');

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';

}

}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。 经导师精心指导并认可、获 98 分的毕业设计项目!【项目资源】:微信小程序。【项目说明】:聚焦计算机相关专业毕设及实战操练,可作课程设计与期末大作业,含全部源码,能直用于毕设,经严格调试,运行有保障!【项目服务】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值