Codeforces 909 C. Python Indentation (DP+树状数组优化)

题目链接:Python Indentation

题意:

  Python是没有大括号来标明语句块的,而是用严格的缩进来体现。现在有一种简化版的Python,只有两种语句:

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

 然后给你一段没有缩进的Python程序,共n行(n <= 5000)。问你添加缩进后,有多少种合法且不同的Python程序。

题解:题目解析

  DP过去,如果第i个位置是‘f‘的话,dp[i][j]只加到dp[i+1][j+1]上,如果是‘s’则可以加到从dp[i][0,j]的所有数上。区间假发可以用树状数组优化,把复杂度降到(n×n×log(n))。这道题让我发现long long操作要比int慢一倍左右,还有MOD操作是真滴慢,遇到MOD操作可以用if降低时间。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAX_N = 5e3+9;
 4 const int MOD = 1e9+7;
 5 char vec[MAX_N];
 6 int dp[MAX_N][MAX_N];
 7 void add(int pos,int x,int num)
 8 {
 9     if(num<0) num+=MOD;
10     for(;x<MAX_N;x+=(x&-x))
11     {
12         dp[pos][x]=dp[pos][x]+num;
13         if(dp[pos][x]>=MOD) dp[pos][x]-=MOD;
14     }
15 }
16 int sum(int pos,int x)
17 {
18     int ans = 0;
19     for(;x>0;x-=(x&-x))
20     {
21         ans=ans+dp[pos][x];
22         if(ans>=MOD) ans-=MOD;
23     }
24     return ans;
25 }
26 int main()
27 {
28     int N,M,T;
29     while(cin>>N)
30     {
31         memset(dp,0,sizeof(dp));
32         for(int i=1;i<=N;i++)
33         {
34             cin>>vec[i];
35         }
36         dp[1][1] = 1;
37         for(int i=1;i<=N;i++)
38         {
39             for(int j=1;j<=i;j++)
40             {
41                 int t = sum(i,j);
42                 if(vec[i] == ‘f‘)
43                 {
44                     add(i+1,j+1,t);
45                     add(i+1,j+2,-t);
46                 }
47                 else
48                 {
49                     add(i+1,1,t);
50                     add(i+1,j+1,-t);
51                 }
52             }
53         }
54         int ans = 0;
55         for(int i=1;i<=N;i++)
56         {
57             ans = ans+sum(N,i);
58             if(ans>=MOD) ans-=MOD;
59         }
60         cout<<(ans+MOD)%MOD<<endl;
61     }
62     return 0;
63 }

原文地址:https://www.cnblogs.com/doggod/p/8387274.html

时间: 2024-09-30 20:43:48

Codeforces 909 C. Python Indentation (DP+树状数组优化)的相关文章

bzoj 3594: [Scoi2014]方伯伯的玉米田 dp树状数组优化

3594: [Scoi2014]方伯伯的玉米田 Time Limit: 60 Sec  Memory Limit: 128 MBSubmit: 314  Solved: 132[Submit][Status] Description 方伯伯在自己的农田边散步,他突然发现田里的一排玉米非常的不美.这排玉米一共有N株,它们的高度参差不齐.方伯伯认为单调不下降序列很美,所以他决定先把一些玉米拔高,再把破坏美感的玉米拔除掉,使得剩下的玉米的高度构成一个单调不下降序列.方伯伯可以选择一个区间,把这个区间的

hdu 2227 dp+树状数组优化

很容易可以想到状态转移方程: dp[i] = segma: dp[j] ( j < i && a[j] <= a[i] ), 其中dp[i]表示以a[i]结尾的不降子序列的个数. 但是n非常大,n^2的算法必然TLE,仔细想想其实式子右边是一个区间和的形式,即小于等于a[i]的a[j]的dp[j]的和,所以可以将a[i]离散化成t后将dp[i]的值存在t位置上,每次求解dp[i]就是查询一个前缀和,可以用树状数组来维护. 举个例子:对于1,50,13,34这四个数,离散化后变成

FZU2236 第十四个目标 dp+树状数组优化

分析:这种题烂大街,n^2,然后数据结构优化下到nlogn,离散化 #include <cstdio> #include <cstring> #include <queue> #include <set> #include <map> #include <stack> #include <cstdlib> #include <algorithm> #include <vector> #include

Codeforces Round #261 (Div. 2) D 树状数组应用

看着题意:[1,i]中等于a[i]的个数要大于[,jn]中等于a[j]的个数 且i<j,求有多少对这样的(i,j)  ,i<j但是 i前面的合法个数 要大于j后面的 看起来很像逆序数的样子,所以很容易往树状数组想去,但是处理就看个人了,像我比赛的时候就处理得非常的麻烦,虽做出了但是花时间也多,经过杰哥的教育,其实正着塞进树状数组 反着来找就可以了,灰常的简单清晰明了,贴一发纪念我的搓比 int n; int aa[1000000 + 55]; int bb[1000000 + 55]; int

HDU 2227 Find the nondecreasing subsequences (DP+树状数组+离散化)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2227 Find the nondecreasing subsequences                                  Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)                                             

Codeforces 374D Inna and Sequence 二分+树状数组

题目链接:点击打开链接 给定n个操作,m长的序列a 下面n个数 if(co>=0)则向字符串添加一个co (开始是空字符串) else 删除字符串中有a的下标的字符 直接在序列上搞,简单模拟 #include<stdio.h> #include<iostream> #include<string.h> #include<set> #include<vector> #include<map> #include<math.h&

树形DP+树状数组 HDU 5877 Weak Pair

1 //树形DP+树状数组 HDU 5877 Weak Pair 2 // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 3 // 这道题要离散化 4 5 #include <bits/stdc++.h> 6 using namespace std; 7 #define LL long long 8 typedef pair<int,int> pii; 9 const double inf = 12345678901234

BZOJ 3790 神奇项链(manacher+DP+树状数组)

[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3790 [题目大意] 问最少用几个回文串可以构成给出串,重叠部分可以合并 [题解] 我们先用manacher处理出每个位置最长的回文串, 那么题目就转化为求最少的线段来覆盖全区间,那就是经典的dp题了, dp[i]=min(dp[j]+1)(i线段的左端点-1和j线段的右端点有交) 用树状数组优化一下即可. [代码] #include <cstdio> #include <al

poj 3616 Milking Time dp+树状数组

题意: 给一堆区间,每个区间有开始时间s,结束时间e,和收益w,现在要找一些区间使收益和最大,且区间之间的间隔最小为r. 分析: 这道题用dp做是简单题,用dp+树状数组做是中等题.dp问题的关键是对状态的定义.有两种方法,一:dp[k]表示按开始时间排序到第k个区间能取得的最大收益.二:dp[t]表示在时间t时能获得的最大收益.定义好状态方程就好写了这不再赘述.有趣的是这个时间复杂度.设一共有M个区间,所有区间的最大时间为L,第一种是M^2的,第二种是M*(logL+logM)的,这题M才10